Skip to content
22 changes: 22 additions & 0 deletions src/Cli.Tests/ValidateConfigTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,26 @@ public void TestConfigWithInvalidConfigProperties()
bool isConfigValid = ConfigGenerator.IsConfigValid(validateOptions, _runtimeConfigLoader!, _fileSystem!);
Assert.IsFalse(isConfigValid);
}

/// <summary>
/// This method validates that the IsConfigValid method returns false when the config is empty.
/// This is to validate that no exceptions are thrown with validate for failures during config deserialization.
/// </summary>
[TestMethod]
public void TestValidateWithEmptyConfig()
{
// create an empty config file
((MockFileSystem)_fileSystem!).AddFile(TEST_RUNTIME_CONFIG_FILE, string.Empty);

ValidateOptions validateOptions = new(TEST_RUNTIME_CONFIG_FILE);

try
{
Assert.IsFalse(ConfigGenerator.IsConfigValid(validateOptions, _runtimeConfigLoader!, _fileSystem!));
}
catch (Exception ex)
{
Assert.Fail($"Unexpected Exception thrown: {ex.Message}");
}
}
}
14 changes: 2 additions & 12 deletions src/Cli/ConfigGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1091,24 +1091,14 @@ public static bool IsConfigValid(ValidateOptions options, FileSystemRuntimeConfi
return false;
}

// Validates that config file has data and it is properly deserialized
// Replaces all the environment variables while deserializing when starting DAB.
if (!loader.TryLoadKnownConfig(out RuntimeConfig? deserializedRuntimeConfig, replaceEnvVar: true))
{
_logger.LogError("Failed to parse the config file: {runtimeConfigFile}.", runtimeConfigFile);
return false;
}
else
{
_logger.LogInformation("Loaded config file: {runtimeConfigFile}", runtimeConfigFile);
}
_logger.LogInformation("Validating config file: {runtimeConfigFile}", runtimeConfigFile);

RuntimeConfigProvider runtimeConfigProvider = new(loader);

ILogger<RuntimeConfigValidator> runtimeConfigValidatorLogger = LoggerFactoryForCli.CreateLogger<RuntimeConfigValidator>();
RuntimeConfigValidator runtimeConfigValidator = new(runtimeConfigProvider, fileSystem, runtimeConfigValidatorLogger, true);

return runtimeConfigValidator.TryValidateConfig(runtimeConfigFile, deserializedRuntimeConfig, LoggerFactoryForCli).Result;
return runtimeConfigValidator.TryValidateConfig(runtimeConfigFile, LoggerFactoryForCli).Result;
}

/// <summary>
Expand Down
14 changes: 9 additions & 5 deletions src/Core/Configurations/RuntimeConfigValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,16 +144,20 @@ public void ValidateAppInsightsTelemetryConnectionString(RuntimeConfig runtimeCo
/// This method is called by the CLI when the user runs `validate` command with `isValidateOnly=true`.
/// </summary>
/// <param name="configFilePath">full/relative config file path with extension</param>
/// <param name="runtimeConfig">RuntimeConfig object</param>
/// <param name="loggerFactory">Logger Factory</param>
/// <param name="isValidateOnly">true if run for validate only mode</param>
/// <returns>true if no validation failures, else false.</returns>
public async Task<bool> TryValidateConfig(
string configFilePath,
RuntimeConfig runtimeConfig,
ILoggerFactory loggerFactory,
bool isValidateOnly = false)
ILoggerFactory loggerFactory)
{
RuntimeConfig? runtimeConfig;

if (!_runtimeConfigProvider.TryGetConfig(out runtimeConfig))
{
_logger.LogInformation("Failed to parse the config file");
return false;
}

JsonSchemaValidationResult validationResult = await ValidateConfigSchema(runtimeConfig, configFilePath, loggerFactory);
ValidateConfigProperties();
ValidatePermissionsInConfig(runtimeConfig);
Expand Down
41 changes: 41 additions & 0 deletions src/Service.Tests/Configuration/ConfigurationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,47 @@ public void TestConfigPropertiesAreValid()
configValidator.ValidateConfigProperties();
}

/// <summary>
/// This method tests that config file is validated correctly and no exceptions are thrown.
/// This tests gets the json from the integration test config file and then uses that
/// to validate the complete config file.
/// </summary>
[TestMethod("Validates the complete config."), TestCategory(TestCategory.MSSQL)]
public async Task TestConfigIsValid()
{
// Fetch the MS_SQL integration test config file.
TestHelper.SetupDatabaseEnvironment(MSSQL_ENVIRONMENT);
FileSystemRuntimeConfigLoader testConfigPath = TestHelper.GetRuntimeConfigLoader();
RuntimeConfig configuration = TestHelper.GetRuntimeConfigProvider(testConfigPath).GetConfig();
const string CUSTOM_CONFIG = "custom-config.json";

MockFileSystem fileSystem = new();

// write it to the custom-config file and add it to the filesystem.
fileSystem.AddFile(CUSTOM_CONFIG, new MockFileData(configuration.ToJson()));
FileSystemRuntimeConfigLoader configLoader = new(fileSystem);
configLoader.UpdateConfigFilePath(CUSTOM_CONFIG);
RuntimeConfigProvider configProvider = TestHelper.GetRuntimeConfigProvider(configLoader);

Mock<ILogger<RuntimeConfigValidator>> configValidatorLogger = new();
RuntimeConfigValidator configValidator =
new(
configProvider,
fileSystem,
configValidatorLogger.Object,
true);

try
{
// Run the validate on the custom config json file.
Assert.IsTrue(await configValidator.TryValidateConfig(CUSTOM_CONFIG, TestHelper.ProvisionLoggerFactory()));
}
catch (Exception e)
{
Assert.Fail(e.Message);
}
}

/// <summary>
/// This test method checks a valid config's entities against
/// the database and ensures they are valid.
Expand Down