feat(mesh-phase5): Telemetry/TelemetryDial options + fail-closed validators
Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user