Skip to content

Commit aa42f5e

Browse files
authored
Feature/override setting with env vars (#16)
* repare a basic implementation of core functionality #1 Author: Alaksiej Mialeška <[email protected]> * replace GetText() with property. make constants internal * fix logging and settings resources. Add some tests * Fix ConditionalWait and tests * add general tests and some documentation. Enhanced Startup for flexibility * fix review comments in LoggerConfiguration and Element * removed internal access modifiers * Set up CI with Azure Pipelines [skip ci] * Update azure-pipelines.yml for Azure Pipelines * Update azure-pipelines.yml for Azure Pipelines * fix webDriverVersion for tests * fix WebDriverVersion dowloaded for tests at azure pipeline. closes #3 * Update azure-pipelines.yml for Azure Pipelines * fix webDriverVersion * fix yml file * Add tests for WinAppDriver and ElementFactory to resolve #5. Related to #6. Corrected Element's public interface * Update azure-pipelines.yml for Azure Pipelines use WinAppDriver task * Update azure-pipelines.yml for Azure Pipelines * replace calc application * Fixed ElementFactoryTests for new application * Feature/abstract application manager (#8) * Extract abstract ApplicationManager from WIndowsApp/ApplicationManager * reworked ApplicationManager for chrome app tests * Enhanced abstract ApplicationManager, add ability to provide custom dependencies. Create tests to ensure that ApplicationManager could have custom dependencies registered in container. * #11 added tests to check overriden settings * #15 added test for ovveriding config with env vars * #15 added fix for Azure * #15 added possibility to get Dictionary from JsonFile with overriden values with Env variables * #15 renamed some method * #15 removed Parallelizable for EnvConfigurationTests removed throw exception in IsValuePresent * #15 added debug test * #15 removed debug test * #15 added string.Empty
1 parent 4387a7f commit aa42f5e

File tree

4 files changed

+136
-38
lines changed

4 files changed

+136
-38
lines changed

Aquality.Selenium.Core/src/Aquality.Selenium.Core/Configurations/LoggerConfiguration.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,17 @@ namespace Aquality.Selenium.Core.Configurations
77
/// </summary>
88
public class LoggerConfiguration : ILoggerConfiguration
99
{
10-
private const string defaultLanguage = "en";
11-
private readonly JsonFile settingsFile;
10+
private const string DefaultLanguage = "en";
1211

1312
/// <summary>
1413
/// Instantiates class using JSON file with general settings.
1514
/// </summary>
1615
/// <param name="settingsFile">JSON settings file.</param>
1716
public LoggerConfiguration(JsonFile settingsFile)
1817
{
19-
this.settingsFile = settingsFile;
18+
Language = settingsFile.GetValueOrDefault(".logger.language", DefaultLanguage);
2019
}
2120

22-
public string Language => settingsFile.GetValueOrDefault(".logger.language", defaultLanguage);
21+
public string Language { get; }
2322
}
2423
}

Aquality.Selenium.Core/src/Aquality.Selenium.Core/Utilities/EnvironmentConfiguration.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ public static string GetVariable(string key)
2020
{
2121
Environment.GetEnvironmentVariable(key),
2222
Environment.GetEnvironmentVariable(key.ToLower()),
23-
Environment.GetEnvironmentVariable(key.ToUpper())
23+
Environment.GetEnvironmentVariable(key.ToUpper()),
24+
//necessary for Azure
25+
Environment.GetEnvironmentVariable(key.ToUpper().Replace('.', '_'))
2426
};
2527
return variables.FirstOrDefault(variable => variable != null);
2628
}

Aquality.Selenium.Core/src/Aquality.Selenium.Core/Utilities/JsonFile.cs

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
using Aquality.Selenium.Core.Logging;
2-
using Newtonsoft.Json;
3-
using Newtonsoft.Json.Linq;
4-
using System;
1+
using System;
52
using System.Collections.Generic;
63
using System.ComponentModel;
74
using System.IO;
85
using System.Linq;
96
using System.Reflection;
7+
using Aquality.Selenium.Core.Logging;
8+
using Newtonsoft.Json;
9+
using Newtonsoft.Json.Linq;
1010

1111
namespace Aquality.Selenium.Core.Utilities
1212
{
@@ -67,23 +67,11 @@ public T GetValue<T>(string jsonPath)
6767
var envValue = GetEnvironmentValue(jsonPath);
6868
if (envValue != null)
6969
{
70-
Logger.Instance.Debug($"***** Using variable passed from environment {jsonPath.Substring(1)}={envValue}");
71-
try
72-
{
73-
return (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(envValue);
74-
}
75-
catch (ArgumentException ex)
76-
{
77-
var message = $"Value of '{jsonPath}' environment variable has incorrect format: {ex.Message}";
78-
throw new ArgumentException(message);
79-
}
70+
return ConvertEnvVar(() => (T) TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(envValue),
71+
envValue, jsonPath);
8072
}
8173

8274
var node = GetJsonNode(jsonPath);
83-
if (node == null)
84-
{
85-
throw new ArgumentException($"There is no value found by path '{jsonPath}' in JSON file '{resourceName}'");
86-
}
8775
return node.ToObject<T>();
8876
}
8977

@@ -101,24 +89,35 @@ public IList<T> GetValueList<T>(string jsonPath)
10189
var envValue = GetEnvironmentValue(jsonPath);
10290
if (envValue != null)
10391
{
104-
Logger.Instance.Debug($"***** Using variable passed from environment {jsonPath.Substring(1)}={envValue}");
105-
try
92+
return ConvertEnvVar(() =>
10693
{
10794
return envValue.Split(',').Select(value => (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(value.Trim())).ToList();
108-
}
109-
catch (ArgumentException ex)
110-
{
111-
var message = $"Value of '{jsonPath}' environment variable has incorrect format: {ex.Message}";
112-
throw new ArgumentException(message);
113-
}
95+
}, envValue, jsonPath);
11496
}
11597

11698
var node = GetJsonNode(jsonPath);
117-
if (node == null)
99+
return node.ToObject<IList<T>>();
100+
}
101+
102+
/// <summary>
103+
/// Gets dictionary of values from JSON.
104+
/// Note that the value can be overriden via Environment variable with the same name;
105+
/// (e.g. for json path ".timeouts.timeoutImplicit" you can set environment variable ".timeouts.timeoutImplicit")
106+
/// </summary>
107+
/// <param name="jsonPath">Relative JsonPath to the values.</param>
108+
/// <typeparam name="T">Type of the value.</typeparam>
109+
/// <returns>Value from JSON/Environment by JsonPath.</returns>
110+
/// <exception cref="ArgumentException">Throws when there are no values found by jsonPath in desired JSON file.</exception>
111+
public IReadOnlyDictionary<string, T> GetValueDictionary<T>(string jsonPath)
112+
{
113+
var dict = new Dictionary<string, T>();
114+
var node = GetJsonNode(jsonPath);;
115+
foreach (var child in node.Children<JProperty>())
118116
{
119-
throw new ArgumentException($"There are no values found by path '{jsonPath}' in JSON file '{resourceName}'");
117+
dict.Add(child.Name, GetValue<T>($".{child.Path}"));
120118
}
121-
return node.ToObject<IList<T>>();
119+
120+
return dict;
122121
}
123122

124123
/// <summary>
@@ -128,18 +127,37 @@ public IList<T> GetValueList<T>(string jsonPath)
128127
/// <returns>True if present and false otherwise.</returns>
129128
public bool IsValuePresent(string jsonPath)
130129
{
131-
return GetEnvironmentValue(jsonPath) != null || GetJsonNode(jsonPath) != null;
130+
return GetEnvironmentValue(jsonPath) != null || JsonObject.SelectToken(jsonPath) != null;
132131
}
133132

134-
private string GetEnvironmentValue(string jsonPath)
133+
private static string GetEnvironmentValue(string jsonPath)
135134
{
136-
var key = jsonPath.Substring(1);
135+
var key = jsonPath.Replace("['", ".").Replace("']", string.Empty).Substring(1);
137136
return EnvironmentConfiguration.GetVariable(key);
138137
}
139138

140139
private JToken GetJsonNode(string jsonPath)
141140
{
142-
return JsonObject.SelectToken(jsonPath);
141+
var node = JsonObject.SelectToken(jsonPath);
142+
if (node == null)
143+
{
144+
throw new ArgumentException($"There are no values found by path '{jsonPath}' in JSON file '{resourceName}'");
145+
}
146+
return node;
147+
}
148+
149+
private static T ConvertEnvVar<T>(Func<T> convertMethod, string envValue, string jsonPath)
150+
{
151+
Logger.Instance.Debug($"***** Using variable passed from environment {jsonPath.Substring(1)}={envValue}");
152+
try
153+
{
154+
return convertMethod();
155+
}
156+
catch (ArgumentException ex)
157+
{
158+
var message = $"Value of '{jsonPath}' environment variable has incorrect format: {ex.Message}";
159+
throw new ArgumentException(message);
160+
}
143161
}
144162
}
145163
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using Aquality.Selenium.Core.Configurations;
2+
using NUnit.Framework;
3+
using System;
4+
using Microsoft.Extensions.DependencyInjection;
5+
6+
namespace Aquality.Selenium.Core.Tests.Configurations
7+
{
8+
[Parallelizable(ParallelScope.None)]
9+
public class EnvConfigurationTests : TestWithoutApplication
10+
{
11+
private const string ProfileVariableName = "profile";
12+
private const string ProfileName = "custom";
13+
14+
[SetUp]
15+
public new void SetUp()
16+
{
17+
Environment.SetEnvironmentVariable(ProfileVariableName, ProfileName);
18+
}
19+
20+
[TearDown]
21+
public void CleanUp()
22+
{
23+
Environment.SetEnvironmentVariable(ProfileVariableName, null);
24+
}
25+
26+
[Test]
27+
public void Should_BePossible_ToOverrideTimeouts_WithEnvVariables()
28+
{
29+
const string testValue = "1000";
30+
var expectedValueSec = TimeSpan.FromSeconds(1000);
31+
var expectedValueMillis = TimeSpan.FromMilliseconds(1000);
32+
const string messageTmp = "{0} timeout should be overridden with env variable";
33+
Environment.SetEnvironmentVariable("timeouts.timeoutImplicit", testValue);
34+
Environment.SetEnvironmentVariable("timeouts.timeoutCondition", testValue);
35+
Environment.SetEnvironmentVariable("timeouts.timeoutPollingInterval", testValue);
36+
Environment.SetEnvironmentVariable("timeouts.timeoutCommand", testValue);
37+
base.SetUp();
38+
39+
var config = ServiceProvider.GetService<ITimeoutConfiguration>();
40+
Assert.Multiple(() =>
41+
{
42+
Assert.AreEqual(expectedValueSec, config.Command, string.Format(messageTmp, "Command"));
43+
Assert.AreEqual(expectedValueSec, config.Condition, string.Format(messageTmp, "Condition"));
44+
Assert.AreEqual(expectedValueSec, config.Implicit, string.Format(messageTmp, "Implicit"));
45+
Assert.AreEqual(expectedValueMillis, config.PollingInterval, string.Format(messageTmp, "PollingInterval"));
46+
});
47+
}
48+
49+
[Test]
50+
public void Should_BePossible_ToOverrideRetryConfig_WithEnvVariables()
51+
{
52+
const string testValue = "1000";
53+
var expectedInterval = TimeSpan.FromMilliseconds(1000);
54+
const int expectedNumber = 1000;
55+
const string messageTmp = "Retry value '{0}' should be overridden with env variable";
56+
Environment.SetEnvironmentVariable("retry.number", testValue);
57+
Environment.SetEnvironmentVariable("retry.pollingInterval", testValue);
58+
base.SetUp();
59+
60+
var config = ServiceProvider.GetService<IRetryConfiguration>();
61+
Assert.Multiple(() =>
62+
{
63+
Assert.AreEqual(expectedInterval, config.PollingInterval, string.Format(messageTmp, "PollingInterval"));
64+
Assert.AreEqual(expectedNumber, config.Number, string.Format(messageTmp, "Number"));
65+
});
66+
}
67+
68+
[Test]
69+
public void Should_BePossible_ToOverrideLoggerConfig_WithEnvVariables()
70+
{
71+
const string testValue = "testLang";
72+
Environment.SetEnvironmentVariable("logger.language", testValue);
73+
base.SetUp();
74+
75+
var config = ServiceProvider.GetService<ILoggerConfiguration>();
76+
Assert.AreEqual(testValue, config.Language, "Logger language value should be overridden with env variable");
77+
}
78+
}
79+
}

0 commit comments

Comments
 (0)