Skip to content

Commit 69f4535

Browse files
[Cherry pick] Fix for Config File Path not found (#1693)
- Cherry Picks #1681 --------- Co-authored-by: abhishekkumams <[email protected]>
1 parent aa103b4 commit 69f4535

File tree

6 files changed

+132
-32
lines changed

6 files changed

+132
-32
lines changed

src/Cli/ConfigGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -965,7 +965,7 @@ public static bool TryStartEngineWithOptions(StartOptions options, FileSystemRun
965965
return false;
966966
}
967967

968-
loader.UpdateConfigFileName(runtimeConfigFile);
968+
loader.UpdateConfigFilePath(runtimeConfigFile);
969969

970970
// Validates that config file has data and follows the correct json schema
971971
// Replaces all the environment variables while deserializing when starting DAB.

src/Cli/ConfigMerger.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public static bool TryMergeConfigsIfAvailable(IFileSystem fileSystem, FileSystem
2424
string baseConfigFile = FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME;
2525
string environmentBasedConfigFile = loader.GetFileName(environmentValue, considerOverrides: false);
2626

27-
if (loader.DoesFileExistInCurrentDirectory(baseConfigFile) && !string.IsNullOrEmpty(environmentBasedConfigFile))
27+
if (loader.DoesFileExistInDirectory(baseConfigFile) && !string.IsNullOrEmpty(environmentBasedConfigFile))
2828
{
2929
try
3030
{

src/Config/FileSystemRuntimeConfigLoader.cs

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ namespace Azure.DataApiBuilder.Config;
2626
public class FileSystemRuntimeConfigLoader : RuntimeConfigLoader
2727
{
2828
// This stores either the default config name e.g. dab-config.json
29-
// or user provided config file.
30-
private string _baseConfigFileName;
29+
// or user provided config file which could be a relative file path, absolute file path or simply the file name assumed to be in current directory.
30+
private string _baseConfigFilePath;
3131

3232
private readonly IFileSystem _fileSystem;
3333

@@ -45,19 +45,20 @@ public class FileSystemRuntimeConfigLoader : RuntimeConfigLoader
4545
public const string DEFAULT_CONFIG_FILE_NAME = $"{CONFIGFILE_NAME}{CONFIG_EXTENSION}";
4646

4747
/// <summary>
48-
/// Stores the config file name actually loaded by the engine.
48+
/// Stores the config file actually loaded by the engine.
4949
/// It could be the base config file (e.g. dab-config.json), any of its derivatives with
5050
/// environment specific suffixes (e.g. dab-config.Development.json) or the user provided
5151
/// config file name.
52+
/// It could also be the config file provided by the user.
5253
/// </summary>
53-
public string ConfigFileName { get; internal set; }
54+
public string ConfigFilePath { get; internal set; }
5455

55-
public FileSystemRuntimeConfigLoader(IFileSystem fileSystem, string baseConfigFileName = DEFAULT_CONFIG_FILE_NAME, string? connectionString = null)
56+
public FileSystemRuntimeConfigLoader(IFileSystem fileSystem, string baseConfigFilePath = DEFAULT_CONFIG_FILE_NAME, string? connectionString = null)
5657
: base(connectionString)
5758
{
5859
_fileSystem = fileSystem;
59-
_baseConfigFileName = baseConfigFileName;
60-
ConfigFileName = GetFileNameForEnvironment(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"), false);
60+
_baseConfigFilePath = baseConfigFilePath;
61+
ConfigFilePath = GetFinalConfigFilePath();
6162
}
6263

6364
/// <summary>
@@ -75,6 +76,7 @@ public bool TryLoadConfig(
7576
{
7677
if (_fileSystem.File.Exists(path))
7778
{
79+
Console.WriteLine($"Loading config file from {path}.");
7880
string json = _fileSystem.File.ReadAllText(path);
7981
return TryParseConfig(json, out config, connectionString: _connectionString, replaceEnvVar: replaceEnvVar);
8082
}
@@ -98,7 +100,7 @@ public bool TryLoadConfig(
98100
/// <returns>True if the config was loaded, otherwise false.</returns>
99101
public override bool TryLoadKnownConfig([NotNullWhen(true)] out RuntimeConfig? config, bool replaceEnvVar = false)
100102
{
101-
return TryLoadConfig(ConfigFileName, out config, replaceEnvVar);
103+
return TryLoadConfig(ConfigFilePath, out config, replaceEnvVar);
102104
}
103105

104106
/// <summary>
@@ -143,6 +145,29 @@ public string GetFileNameForEnvironment(string? aspnetEnvironment, bool consider
143145
return configFileNameWithExtension;
144146
}
145147

148+
/// <summary>
149+
/// This method returns the final config file name that will be used by the runtime engine.
150+
/// </summary>
151+
private string GetFinalConfigFilePath()
152+
{
153+
if (!string.Equals(_baseConfigFilePath, DEFAULT_CONFIG_FILE_NAME))
154+
{
155+
// user provided config file is honoured.
156+
return _baseConfigFilePath;
157+
}
158+
159+
// ConfigFile not explicitly provided by user, so we need to get the config file name based on environment.
160+
string configFilePath = GetFileNameForEnvironment(Environment.GetEnvironmentVariable(ASP_NET_CORE_ENVIRONMENT_VAR_NAME), false);
161+
162+
// If file for environment is not found, then the baseConfigFile is used as the final configFile for runtime engine.
163+
if (string.IsNullOrWhiteSpace(configFilePath))
164+
{
165+
return _baseConfigFilePath;
166+
}
167+
168+
return configFilePath;
169+
}
170+
146171
/// <summary>
147172
/// Generates the config file name and a corresponding overridden file name,
148173
/// With precedence given to overridden file name, returns that name
@@ -154,31 +179,34 @@ public string GetFileNameForEnvironment(string? aspnetEnvironment, bool consider
154179
/// <returns></returns>
155180
public string GetFileName(string? environmentValue, bool considerOverrides)
156181
{
157-
string fileNameWithoutExtension = _fileSystem.Path.GetFileNameWithoutExtension(_baseConfigFileName);
158-
string fileExtension = _fileSystem.Path.GetExtension(_baseConfigFileName);
159-
string configFileName =
182+
// If the baseConfigFilePath contains directory info, we need to ensure that it is not lost. for example: baseConfigFilePath = "config/dab-config.json"
183+
// in this case, we need to get the directory name and the file name without extension and then combine them back. Else, we will lose the path
184+
// and the file will be searched in the current directory.
185+
string filePathWithoutExtension = _fileSystem.Path.Combine(_fileSystem.Path.GetDirectoryName(_baseConfigFilePath) ?? string.Empty, _fileSystem.Path.GetFileNameWithoutExtension(_baseConfigFilePath));
186+
string fileExtension = _fileSystem.Path.GetExtension(_baseConfigFilePath);
187+
string configFilePath =
160188
!string.IsNullOrEmpty(environmentValue)
161-
? $"{fileNameWithoutExtension}.{environmentValue}"
162-
: $"{fileNameWithoutExtension}";
163-
string configFileNameWithExtension = $"{configFileName}{fileExtension}";
164-
string overriddenConfigFileNameWithExtension = GetOverriddenName(configFileName);
189+
? $"{filePathWithoutExtension}.{environmentValue}"
190+
: $"{filePathWithoutExtension}";
191+
string configFileNameWithExtension = $"{configFilePath}{fileExtension}";
192+
string overriddenConfigFileNameWithExtension = GetOverriddenName(configFilePath);
165193

166-
if (considerOverrides && DoesFileExistInCurrentDirectory(overriddenConfigFileNameWithExtension))
194+
if (considerOverrides && DoesFileExistInDirectory(overriddenConfigFileNameWithExtension))
167195
{
168196
return overriddenConfigFileNameWithExtension;
169197
}
170198

171-
if (DoesFileExistInCurrentDirectory(configFileNameWithExtension))
199+
if (DoesFileExistInDirectory(configFileNameWithExtension))
172200
{
173201
return configFileNameWithExtension;
174202
}
175203

176204
return string.Empty;
177205
}
178206

179-
private static string GetOverriddenName(string fileName)
207+
private static string GetOverriddenName(string filePath)
180208
{
181-
return $"{fileName}.overrides{CONFIG_EXTENSION}";
209+
return $"{filePath}.overrides{CONFIG_EXTENSION}";
182210
}
183211

184212
/// <summary>
@@ -190,10 +218,16 @@ public static string GetEnvironmentFileName(string fileName, string environmentV
190218
return $"{fileName}.{environmentValue}{CONFIG_EXTENSION}";
191219
}
192220

193-
public bool DoesFileExistInCurrentDirectory(string fileName)
221+
/// <summary>
222+
/// Checks if the file exists in the directory.
223+
/// Works for both relative and absolute paths.
224+
/// </summary>
225+
/// <param name="filePath"></param>
226+
/// <returns>True if file is found, else false.</returns>
227+
public bool DoesFileExistInDirectory(string filePath)
194228
{
195229
string currentDir = _fileSystem.Directory.GetCurrentDirectory();
196-
return _fileSystem.File.Exists(_fileSystem.Path.Combine(currentDir, fileName));
230+
return _fileSystem.File.Exists(_fileSystem.Path.Combine(currentDir, filePath));
197231
}
198232

199233
/// <summary>
@@ -256,9 +290,9 @@ public static string GetMergedFileNameForEnvironment(string fileName, string env
256290
/// to be updated. This is commonly done when the CLI is starting up.
257291
/// </summary>
258292
/// <param name="fileName"></param>
259-
public void UpdateConfigFileName(string fileName)
293+
public void UpdateConfigFilePath(string filePath)
260294
{
261-
_baseConfigFileName = fileName;
262-
ConfigFileName = fileName;
295+
_baseConfigFilePath = filePath;
296+
ConfigFilePath = filePath;
263297
}
264298
}

src/Service.Tests/Configuration/AuthenticationConfigValidatorUnitTests.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public void ValidateEasyAuthConfig()
4747

4848
// Since we added the config file to the filesystem above after the config loader was initialized
4949
// in TestInitialize, we need to update the ConfigfileName, otherwise it will be an empty string.
50-
_runtimeConfigLoader.UpdateConfigFileName(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME);
50+
_runtimeConfigLoader.UpdateConfigFilePath(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME);
5151

5252
try
5353
{
@@ -75,7 +75,7 @@ public void ValidateJwtConfigParamsSet()
7575
new MockFileData(config.ToJson())
7676
);
7777

78-
_runtimeConfigLoader.UpdateConfigFileName(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME);
78+
_runtimeConfigLoader.UpdateConfigFilePath(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME);
7979

8080
try
8181
{
@@ -96,7 +96,7 @@ public void ValidateAuthNSectionNotNecessary()
9696
new MockFileData(config.ToJson())
9797
);
9898

99-
_runtimeConfigLoader.UpdateConfigFileName(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME);
99+
_runtimeConfigLoader.UpdateConfigFilePath(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME);
100100

101101
try
102102
{
@@ -125,7 +125,7 @@ public void ValidateFailureWithIncompleteJwtConfig()
125125
new MockFileData(config.ToJson())
126126
);
127127

128-
_runtimeConfigLoader.UpdateConfigFileName(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME);
128+
_runtimeConfigLoader.UpdateConfigFilePath(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME);
129129

130130
Assert.ThrowsException<NotSupportedException>(() =>
131131
{
@@ -160,7 +160,7 @@ public void ValidateFailureWithUnneededEasyAuthConfig()
160160
new MockFileData(config.ToJson())
161161
);
162162

163-
_runtimeConfigLoader.UpdateConfigFileName(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME);
163+
_runtimeConfigLoader.UpdateConfigFilePath(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME);
164164

165165
Assert.ThrowsException<NotSupportedException>(() =>
166166
{

src/Service.Tests/Unittests/ConfigValidationUnitTests.cs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System;
66
using System.Collections.Generic;
77
using System.Data;
8+
using System.IO;
89
using System.IO.Abstractions.TestingHelpers;
910
using System.Linq;
1011
using System.Net;
@@ -2016,6 +2017,71 @@ public void ValidateRuntimeBaseRouteSettings(
20162017
}
20172018
}
20182019

2020+
/// <summary>
2021+
/// This test checks that the final config used by runtime engine doesn't lose the directory information
2022+
/// if provided by the user.
2023+
/// It also validates that if config file is provided by the user, it will be used directly irrespective of
2024+
/// environment variable being set or not.
2025+
/// When user doesn't provide a config file, we check if environment variable is set and if it is, we use
2026+
/// the config file specified by the environment variable, else we use the default config file.
2027+
/// <param name="userProvidedConfigFilePath"></param>
2028+
/// <param name="environmentValue"></param>
2029+
/// <param name="useAbsolutePath"></param>
2030+
/// <param name="environmentFile"></param>
2031+
/// <param name="finalConfigFilePath"></param>
2032+
[DataTestMethod]
2033+
[DataRow("my-config.json", "", false, null, "my-config.json", DisplayName = "Config file in the current directory provided by user and environment variable is not set")]
2034+
[DataRow("test-configs/my-config.json", "", false, null, "test-configs/my-config.json", DisplayName = "Config file in different directory provided by user and environment variable is not set")]
2035+
[DataRow("my-config.json", "Test", false, "my-config.Test.json", "my-config.json", DisplayName = "Config file in the current directory provided by user and environment variable is set")]
2036+
[DataRow("test-configs/my-config.json", "Test", false, "test-configs/my-config.Test.json", "test-configs/my-config.json", DisplayName = "Config file in different directory provided by user and environment variable is set")]
2037+
[DataRow("my-config.json", "Test", false, "dab-config.Test.json", "my-config.json", DisplayName = "Config file in the current directory provided by user and environment variable is set and environment file is present")]
2038+
[DataRow("test-configs/my-config.json", "Test", false, "test-configs/dab-config.Test.json", "test-configs/my-config.json", DisplayName = "Config file in different directory provided by user and environment variable is set and environment file is present")]
2039+
[DataRow("my-config.json", "", true, null, "my-config.json", DisplayName = "Config file in the current directory provided by user and environment variable is not set and absolute path is provided")]
2040+
[DataRow("test-configs/my-config.json", "", true, null, "test-configs/my-config.json", DisplayName = "Config file in different directory provided by user and environment variable is not set and absolute path is provided")]
2041+
[DataRow("my-config.json", "Test", true, "my-config.Test.json", "my-config.json", DisplayName = "Config file in the current directory provided by user and environment variable is set and absolute path is provided")]
2042+
[DataRow("test-configs/my-config.json", "Test", true, "test-configs/my-config.Test.json", "test-configs/my-config.json", DisplayName = "Config file in different directory provided by user and environment variable is set and absolute path is provided")]
2043+
[DataRow("my-config.json", "Test", true, "dab-config.Test.json", "my-config.json", DisplayName = "Config file in the current directory provided by user and environment variable is set and environment file is present and absolute path is provided")]
2044+
[DataRow("test-configs/my-config.json", "Test", true, "test-configs/dab-config.Test.json", "test-configs/my-config.json", DisplayName = "Config file in the different directory provided by user and environment variable is set and environment file is present and absolute path is provided")]
2045+
[DataRow(null, "", false, null, "dab-config.json", DisplayName = "Config file not provided by user and environment variable is not set")]
2046+
[DataRow(null, "Test", false, "dab-config.Test.json", "dab-config.json", DisplayName = "Config file not provided by user and environment variable is set and environment file is present")]
2047+
[DataRow(null, "Test", false, null, "dab-config.json", DisplayName = "Config file not provided by user and environment variable is set and environment file is not present")]
2048+
public void TestCorrectConfigFileIsSelectedForRuntimeEngine(
2049+
string userProvidedConfigFilePath,
2050+
string environmentValue,
2051+
bool useAbsolutePath,
2052+
string environmentFile,
2053+
string finalConfigFilePath)
2054+
{
2055+
MockFileSystem fileSystem = new();
2056+
if (!string.IsNullOrWhiteSpace(Path.GetDirectoryName(userProvidedConfigFilePath)))
2057+
{
2058+
fileSystem.AddDirectory("test-configs");
2059+
}
2060+
2061+
if (useAbsolutePath)
2062+
{
2063+
userProvidedConfigFilePath = fileSystem.Path.GetFullPath(userProvidedConfigFilePath);
2064+
finalConfigFilePath = fileSystem.Path.GetFullPath(finalConfigFilePath);
2065+
}
2066+
2067+
if (environmentFile is not null)
2068+
{
2069+
fileSystem.AddEmptyFile(environmentFile);
2070+
}
2071+
2072+
FileSystemRuntimeConfigLoader runtimeConfigLoader;
2073+
if (userProvidedConfigFilePath is not null)
2074+
{
2075+
runtimeConfigLoader = new(fileSystem, userProvidedConfigFilePath);
2076+
}
2077+
else
2078+
{
2079+
runtimeConfigLoader = new(fileSystem);
2080+
}
2081+
2082+
Assert.AreEqual(finalConfigFilePath, runtimeConfigLoader.ConfigFilePath);
2083+
}
2084+
20192085
private static RuntimeConfigValidator InitializeRuntimeConfigValidator()
20202086
{
20212087
MockFileSystem fileSystem = new();

src/Service/Startup.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, RuntimeC
303303
_logger.LogError("Exiting the runtime engine...");
304304
}
305305

306-
throw new ApplicationException($"Could not initialize the engine with the runtime config file: {fileSystemRuntimeConfigLoader.ConfigFileName}");
306+
throw new ApplicationException($"Could not initialize the engine with the runtime config file: {fileSystemRuntimeConfigLoader.ConfigFilePath}");
307307
}
308308
}
309309
else

0 commit comments

Comments
 (0)