513fa1aa16
Comment/XML-doc changes only: - add summaries to ~10k test methods, fixtures, fakes and helpers (+ <param> on theories, <returns> on async Task methods, <inheritdoc/> on interface implementations the checker can resolve) - strip ~2.6k project-tracking references (WP*, P*-*, row-NN, Task N, #NN, Component-0NN) from comments, keeping the explanatory text; reword false positives in comments only - real docs on fakes implementing BCL/library interfaces (IDisposable, ILogger, IOptionsMonitor, IAsyncLifetime) - reword the last 5 src/ false positives (CWE-1236, failures-1, year-0001, M365) Only non-comment edits: four one-line nested classes split across lines so members can carry docs. Build 0 errors / 0 warnings.
120 lines
4.6 KiB
C#
120 lines
4.6 KiB
C#
using ZB.MOM.WW.ScadaBridge.Host;
|
|
|
|
namespace ZB.MOM.WW.ScadaBridge.Host.Tests;
|
|
|
|
/// <summary>
|
|
/// Eager startup validation for the shared Host options (arch-review 08 round 2
|
|
/// NF4). Covers <see cref="NodeOptionsValidator"/>,
|
|
/// <see cref="DatabaseOptionsValidator"/>, and
|
|
/// <see cref="LoggingOptionsValidator"/> in one file. The headline case: an
|
|
/// empty <see cref="NodeOptions.NodeName"/> normalises to a NULL SourceNode
|
|
/// audit column, so it must fail the host at boot rather than silently degrade
|
|
/// the audit trail.
|
|
/// </summary>
|
|
public class NodeOptionsValidatorTests
|
|
{
|
|
// ---- NodeOptions ----
|
|
|
|
/// <summary>Verifies that default node options with a node name are valid.</summary>
|
|
[Fact]
|
|
public void Node_DefaultsWithNodeName_AreValid()
|
|
{
|
|
var validator = new NodeOptionsValidator();
|
|
Assert.True(validator.Validate(null, new NodeOptions { NodeName = "node-a" }).Succeeded);
|
|
}
|
|
|
|
/// <summary>Verifies that an empty or whitespace node name fails validation.</summary>
|
|
/// <param name="nodeName">The invalid node name.</param>
|
|
[Theory]
|
|
[InlineData("")]
|
|
[InlineData(" ")]
|
|
public void Node_EmptyOrWhitespaceNodeName_Fails(string nodeName)
|
|
{
|
|
var validator = new NodeOptionsValidator();
|
|
var result = validator.Validate(null, new NodeOptions { NodeName = nodeName });
|
|
Assert.False(result.Succeeded);
|
|
Assert.Contains(result.Failures!,
|
|
f => f.Contains(nameof(NodeOptions.NodeName), StringComparison.Ordinal));
|
|
}
|
|
|
|
/// <summary>Verifies that a remoting port of zero is valid.</summary>
|
|
[Fact]
|
|
public void Node_ZeroRemotingPort_IsValid()
|
|
{
|
|
// CompositionRootTests uses RemotingPort = 0 to request a dynamic port.
|
|
var validator = new NodeOptionsValidator();
|
|
Assert.True(validator.Validate(null,
|
|
new NodeOptions { NodeName = "node-a", RemotingPort = 0 }).Succeeded);
|
|
}
|
|
|
|
/// <summary>Verifies that a remoting port outside the valid range fails validation.</summary>
|
|
/// <param name="port">The out-of-range port number.</param>
|
|
[Theory]
|
|
[InlineData(-1)]
|
|
[InlineData(65_536)]
|
|
public void Node_PortOutOfRange_Fails(int port)
|
|
{
|
|
var validator = new NodeOptionsValidator();
|
|
var result = validator.Validate(null,
|
|
new NodeOptions { NodeName = "node-a", GrpcPort = port });
|
|
Assert.False(result.Succeeded);
|
|
Assert.Contains(result.Failures!,
|
|
f => f.Contains(nameof(NodeOptions.GrpcPort), StringComparison.Ordinal));
|
|
}
|
|
|
|
// ---- DatabaseOptions ----
|
|
|
|
/// <summary>Verifies that database options with all values null are valid.</summary>
|
|
[Fact]
|
|
public void Database_AllNull_IsValid()
|
|
{
|
|
// All three fields are nullable and role-dependent; null stays valid.
|
|
var validator = new DatabaseOptionsValidator();
|
|
Assert.True(validator.Validate(null, new DatabaseOptions()).Succeeded);
|
|
}
|
|
|
|
/// <summary>Verifies that a whitespace database value fails validation.</summary>
|
|
[Fact]
|
|
public void Database_WhitespaceValue_Fails()
|
|
{
|
|
var validator = new DatabaseOptionsValidator();
|
|
var result = validator.Validate(null, new DatabaseOptions { ConfigurationDb = " " });
|
|
Assert.False(result.Succeeded);
|
|
Assert.Contains(result.Failures!,
|
|
f => f.Contains(nameof(DatabaseOptions.ConfigurationDb), StringComparison.Ordinal));
|
|
}
|
|
|
|
// ---- LoggingOptions ----
|
|
|
|
/// <summary>Verifies that the default Information logging level is valid.</summary>
|
|
[Fact]
|
|
public void Logging_DefaultInformation_IsValid()
|
|
{
|
|
var validator = new LoggingOptionsValidator();
|
|
Assert.True(validator.Validate(null, new LoggingOptions()).Succeeded);
|
|
}
|
|
|
|
/// <summary>Verifies that a recognised logging level is valid.</summary>
|
|
/// <param name="level">The logging level name.</param>
|
|
[Theory]
|
|
[InlineData("Verbose")]
|
|
[InlineData("debug")]
|
|
[InlineData("FATAL")]
|
|
public void Logging_RecognisedLevel_IsValid(string level)
|
|
{
|
|
var validator = new LoggingOptionsValidator();
|
|
Assert.True(validator.Validate(null, new LoggingOptions { MinimumLevel = level }).Succeeded);
|
|
}
|
|
|
|
/// <summary>Verifies that an unknown logging level fails validation.</summary>
|
|
[Fact]
|
|
public void Logging_UnknownLevel_Fails()
|
|
{
|
|
var validator = new LoggingOptionsValidator();
|
|
var result = validator.Validate(null, new LoggingOptions { MinimumLevel = "Chatty" });
|
|
Assert.False(result.Succeeded);
|
|
Assert.Contains(result.Failures!,
|
|
f => f.Contains(nameof(LoggingOptions.MinimumLevel), StringComparison.Ordinal));
|
|
}
|
|
}
|