test(mesh): step 7 — replace the boundary test with MeshGrpcBoundaryTests and sweep the comments

MeshGrpcBoundaryTests replaces the MeshClusterClientBoundaryTests deleted in step 1. Three
self-seeded single-member clusters sharing the ActorSystem name, joined ONLY by gRPC, driving
the REAL CentralCommunicationActor -> MeshGrpcCommandDialer -> Kestrel h2c ->
MeshCommandAuthInterceptor -> NodeCommandGrpcService -> NodeCommunicationActor -> EventStream:

  1. No_cross_mesh_Akka_association_forms_between_central_and_either_site — the program's own
     point, kept as a test rather than a live-gate note: each cluster stays single-member and
     none ever holds another's address as a member.
  2. One_dispatch_through_central_reaches_a_node_in_every_cluster_mesh — the fan, with each
     site holding its OWN per-cluster PSK, so a dial that selected the wrong cluster's key
     would be refused at the far side.
  3. Falsifiability_control_a_dial_carrying_the_wrong_cluster_key_delivers_nothing — without
     it, (2) cannot distinguish "the gRPC boundary carried it" from "something else in the
     process did". The same node then accepts the right key, so the silence is the auth gate
     and not a dead endpoint.

All three run fully offline — no Docker fixture — and pass.

Comment sweep across every remaining clusterclient|receptionist hit in src/ and tests/:
the program label becomes "mesh gRPC command plane", and every comment that described the
deleted transport as live now describes what actually runs (Dps = pair-local default,
Grpc = cross-mesh). mesh_transport.proto's header/service comments are reworded; no message,
field or enum is touched — the contract is locked. MeshCommActorPathTests is reshaped rather
than retired: the two paths still exist and still matter, but what a mismatch costs is now a
misleading Unavailable from the gRPC ingress rather than a silently dropped receptionist send.

The only surviving mentions of the old names are the ones that must survive: the fail-closed
rules that name "ClusterClient" as a retired value refused at boot, their tests, and this
test class's own account of what it replaces.
This commit is contained in:
Joseph Doherty
2026-08-06 15:58:36 -04:00
parent af3b0c3146
commit 4d2dfb5b50
33 changed files with 505 additions and 86 deletions
@@ -64,10 +64,10 @@ public class MeshTransportOptionsValidatorTests
[Fact]
public void Unknown_mode_fails()
{
var result = Validate(new MeshTransportOptions { Mode = "receptionist" });
var result = Validate(new MeshTransportOptions { Mode = "not-a-transport" });
result.Failed.ShouldBeTrue();
result.FailureMessage.ShouldContain("receptionist");
result.FailureMessage.ShouldContain("not-a-transport");
}
[Fact]
@@ -94,7 +94,7 @@ public class SplitTopologyTransportValidatorTests
// still a mode that delivers nothing across the boundary. The retired 'ClusterClient' value
// lands here too.
var result = Validate(
meshMode: "receptionist",
meshMode: "not-a-transport",
telemetryMode: TelemetryOptions.ModeGrpc,
telemetryDialMode: null,
"driver", "cluster-SITE-A");
@@ -12,7 +12,7 @@ using ZB.MOM.WW.OtOpcUa.Commons.Types;
namespace ZB.MOM.WW.OtOpcUa.Commons.Tests;
/// <summary>
/// Round-trip goldens for <see cref="MeshTransportDtoMapper"/> — the ClusterClient→gRPC command
/// Round-trip goldens for <see cref="MeshTransportDtoMapper"/> — the mesh gRPC command
/// plane's only data contract. Every golden goes domain → proto → <b>serialized bytes</b> → proto →
/// domain, because the failure class this suite exists to catch is not a mis-assigned property but a
/// member that survives an in-memory copy and vanishes on the wire: proto3 explicit presence is a
@@ -6,7 +6,7 @@ using ZB.MOM.WW.OtOpcUa.Commons.Protos.MeshTransport.V1;
namespace ZB.MOM.WW.OtOpcUa.Commons.Tests;
/// <summary>
/// Contract-lock for the ClusterClient→gRPC command envelope's oneof. If a fifth command is added
/// Contract-lock for the mesh command envelope's oneof. If a fifth command is added
/// to <c>mesh_transport.proto</c> without adding a matching entry to
/// <see cref="MeshTransportProtoContract.HandledCases"/>, this test goes red — the single guard
/// that keeps the wire contract and the handled-case set from silently drifting apart. A drift
@@ -9,7 +9,7 @@ namespace ZB.MOM.WW.OtOpcUa.Configuration.Tests;
/// <summary>
/// Round-trips <see cref="ClusterNode.AkkaPort"/> / <see cref="ClusterNode.GrpcPort"/> through
/// the real schema (per-cluster mesh Phase 1). These are <b>central's dial targets</b>: Phase 2
/// builds its ClusterClient contact points from <c>Host</c> + <c>AkkaPort</c>, and Phase 5 dials
/// built its Akka contact points from <c>Host</c> + <c>AkkaPort</c>, and Phase 5 dials
/// <c>GrpcPort</c> for the telemetry stream. Central cannot see a site node's appsettings once
/// the meshes split, so the value has to live in a row central can read.
/// </summary>