Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Fix handling of GlobalOptions deserializing to null #1917

Merged
merged 6 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/1917-bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix handling of GlobalOptions deserializing to null
23 changes: 12 additions & 11 deletions src/SmiServices/Common/Options/GlobalOptionsFactory.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Abstractions;
using YamlDotNet.Serialization;

namespace SmiServices.Common.Options
Expand Down Expand Up @@ -28,24 +29,23 @@ public GlobalOptionsFactory(
/// </summary>
/// <param name="hostProcessName"></param>
/// <param name="configFilePath"></param>
/// <param name="fileSystem"></param>
/// <returns></returns>
public GlobalOptions Load(string hostProcessName, string configFilePath = "default.yaml")
public GlobalOptions Load(string hostProcessName, string configFilePath = "default.yaml", IFileSystem? fileSystem = null)
{
fileSystem ??= new FileSystem();

IDeserializer deserializer = new DeserializerBuilder()
.WithObjectFactory(GetGlobalOption)
.IgnoreUnmatchedProperties()
.Build();

if (!File.Exists(configFilePath))
if (!fileSystem.File.Exists(configFilePath))
throw new ArgumentException($"Could not find config file '{configFilePath}'");

string yamlContents = File.ReadAllText(configFilePath);

using var sr = new StringReader(yamlContents);
var globals = deserializer.Deserialize<GlobalOptions>(sr);

if (globals.LoggingOptions == null)
throw new Exception($"Loaded YAML did not contain a {nameof(globals.LoggingOptions)} key. Did you provide a valid config file?");
var yamlContents = fileSystem.File.ReadAllText(configFilePath);
var globals = deserializer.Deserialize<GlobalOptions?>(yamlContents)
?? throw new Exception("Did not deserialize a GlobalOptions object from the provided YAML file. Does it contain at least one valid key?");

globals.HostProcessName = hostProcessName;

Expand All @@ -70,10 +70,11 @@ private GlobalOptions Decorate(GlobalOptions globals)
/// </summary>
/// <param name="hostProcessName"></param>
/// <param name="cliOptions"></param>
/// <param name="fileSystem"></param>
/// <returns></returns>
public GlobalOptions Load(string hostProcessName, CliOptions cliOptions)
public GlobalOptions Load(string hostProcessName, CliOptions cliOptions, IFileSystem? fileSystem = null)
{
GlobalOptions globalOptions = Load(hostProcessName, cliOptions.YamlFile);
GlobalOptions globalOptions = Load(hostProcessName, cliOptions.YamlFile, fileSystem);

// The above Load call does the decoration - don't do it here.
return globalOptions;
Expand Down
24 changes: 22 additions & 2 deletions tests/SmiServices.IntegrationTests/Common/OptionsTests.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@

using NUnit.Framework;
using SmiServices.Common.Options;
using System;
using System.Collections.Generic;
using System.IO.Abstractions.TestingHelpers;

namespace SmiServices.UnitTests.Common
{
Expand Down Expand Up @@ -84,5 +83,26 @@ public void TestDecorators()
Assert.That(g.MongoDatabases.ExtractionStoreOptions!.DatabaseName, Is.EqualTo("FFFFF"));
});
}

[Test]
public void GlobalOptionsFactory_Load_EmptyFile_ThrowsWithUsefulMessage()
{
var fileSystem = new MockFileSystem();
fileSystem.File.Create("foo.yaml");
var globalOptionsFactory = new GlobalOptionsFactory();

var exc = Assert.Throws<Exception>(() => globalOptionsFactory.Load(nameof(GlobalOptionsFactory_Load_EmptyFile_ThrowsWithUsefulMessage), "foo.yaml", fileSystem));
Assert.That(exc.Message, Is.EqualTo("Did not deserialize a GlobalOptions object from the provided YAML file. Does it contain at least one valid key?"));
}

[Test]
public void GlobalOptionsFactory_Load_MissingFile_ThrowsWithUsefulMessage()
{
var fileSystem = new MockFileSystem();
var globalOptionsFactory = new GlobalOptionsFactory();

var exc = Assert.Throws<ArgumentException>(() => globalOptionsFactory.Load(nameof(GlobalOptionsFactory_Load_EmptyFile_ThrowsWithUsefulMessage), "foo.yaml", fileSystem));
Assert.That(exc.Message, Is.EqualTo("Could not find config file 'foo.yaml'"));
}
}
}
Loading