53ae0100a2
Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW
158 lines
4.9 KiB
C#
158 lines
4.9 KiB
C#
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.Options;
|
|
using Shouldly;
|
|
using Xunit;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Cluster.Tests;
|
|
|
|
/// <summary>
|
|
/// A Grpc-mode node with no listen port or no key does not error — it simply never serves
|
|
/// telemetry, and whoever is watching sees nothing with no stack trace to point at. These tests
|
|
/// make that misconfiguration a loud host-start failure instead.
|
|
/// </summary>
|
|
public class TelemetryOptionsValidatorTests
|
|
{
|
|
private static ValidateOptionsResult Validate(TelemetryOptions o, params string[] roles)
|
|
{
|
|
var pairs = new Dictionary<string, string?>();
|
|
for (var i = 0; i < roles.Length; i++)
|
|
{
|
|
pairs[$"Cluster:Roles:{i}"] = roles[i];
|
|
}
|
|
|
|
var configuration = new ConfigurationBuilder().AddInMemoryCollection(pairs).Build();
|
|
|
|
return new TelemetryOptionsValidator(configuration).Validate(TelemetryOptions.SectionName, o);
|
|
}
|
|
|
|
[Fact]
|
|
public void Default_options_are_valid()
|
|
{
|
|
Validate(new TelemetryOptions()).Succeeded.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void Unknown_mode_fails()
|
|
{
|
|
var result = Validate(new TelemetryOptions { Mode = "stream" });
|
|
|
|
result.Failed.ShouldBeTrue();
|
|
result.FailureMessage.ShouldContain("stream");
|
|
}
|
|
|
|
[Fact]
|
|
public void Mode_matching_is_case_insensitive()
|
|
{
|
|
Validate(new TelemetryOptions
|
|
{
|
|
Mode = "grpc",
|
|
GrpcListenPort = 5100,
|
|
ApiKey = "k",
|
|
}, "driver").Succeeded.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void Grpc_driver_node_with_no_listen_port_fails()
|
|
{
|
|
var result = Validate(
|
|
new TelemetryOptions { Mode = TelemetryOptions.ModeGrpc, ApiKey = "k" },
|
|
"driver");
|
|
|
|
result.Failed.ShouldBeTrue();
|
|
result.FailureMessage.ShouldContain(nameof(TelemetryOptions.GrpcListenPort));
|
|
}
|
|
|
|
[Fact]
|
|
public void Grpc_with_empty_key_fails()
|
|
{
|
|
var result = Validate(
|
|
new TelemetryOptions { Mode = TelemetryOptions.ModeGrpc, GrpcListenPort = 5100, ApiKey = "" },
|
|
"driver");
|
|
|
|
result.Failed.ShouldBeTrue();
|
|
result.FailureMessage.ShouldContain(nameof(TelemetryOptions.ApiKey));
|
|
}
|
|
|
|
[Fact]
|
|
public void Grpc_driver_with_port_and_key_is_valid()
|
|
{
|
|
Validate(
|
|
new TelemetryOptions { Mode = TelemetryOptions.ModeGrpc, GrpcListenPort = 5100, ApiKey = "k" },
|
|
"driver").Succeeded.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void Grpc_admin_only_node_does_not_require_a_listen_port()
|
|
{
|
|
// The listen-port requirement is driver-specific — an admin-only node dialling out (via
|
|
// TelemetryDialOptions) never serves, so it has nothing to bind.
|
|
Validate(
|
|
new TelemetryOptions { Mode = TelemetryOptions.ModeGrpc, ApiKey = "k" },
|
|
"admin").Succeeded.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void Grpc_with_no_roles_does_not_require_a_key()
|
|
{
|
|
// Fail-closed only applies to a node that actually carries a role — a roleless node hosts
|
|
// nothing to protect.
|
|
Validate(new TelemetryOptions { Mode = TelemetryOptions.ModeGrpc, ApiKey = "" })
|
|
.Succeeded.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void Dps_ignores_the_empty_grpc_surface()
|
|
{
|
|
Validate(
|
|
new TelemetryOptions { Mode = TelemetryOptions.ModeDps, GrpcListenPort = 0, ApiKey = "" },
|
|
"driver").Succeeded.ShouldBeTrue();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Mirrors <see cref="TelemetryOptionsValidatorTests"/> for the central dial-side options.
|
|
/// </summary>
|
|
public class TelemetryDialOptionsValidatorTests
|
|
{
|
|
private static ValidateOptionsResult Validate(TelemetryDialOptions o) =>
|
|
new TelemetryDialOptionsValidator().Validate(TelemetryDialOptions.SectionName, o);
|
|
|
|
[Fact]
|
|
public void Default_options_are_valid()
|
|
{
|
|
Validate(new TelemetryDialOptions()).Succeeded.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void Unknown_mode_fails()
|
|
{
|
|
var result = Validate(new TelemetryDialOptions { Mode = "poll" });
|
|
|
|
result.Failed.ShouldBeTrue();
|
|
result.FailureMessage.ShouldContain("poll");
|
|
}
|
|
|
|
[Fact]
|
|
public void Grpc_with_empty_key_fails()
|
|
{
|
|
var result = Validate(new TelemetryDialOptions { Mode = TelemetryDialOptions.ModeGrpc, ApiKey = "" });
|
|
|
|
result.Failed.ShouldBeTrue();
|
|
result.FailureMessage.ShouldContain(nameof(TelemetryDialOptions.ApiKey));
|
|
}
|
|
|
|
[Fact]
|
|
public void Grpc_with_a_key_is_valid()
|
|
{
|
|
Validate(new TelemetryDialOptions { Mode = TelemetryDialOptions.ModeGrpc, ApiKey = "k" })
|
|
.Succeeded.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void Dps_ignores_the_empty_key()
|
|
{
|
|
Validate(new TelemetryDialOptions { Mode = TelemetryDialOptions.ModeDps, ApiKey = "" })
|
|
.Succeeded.ShouldBeTrue();
|
|
}
|
|
}
|