From f3832aa48c7364f0f466689f0bfe177541a2e283 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 20 Aug 2026 10:25:02 -0400 Subject: [PATCH] test(host): a mesh gRPC map added outside MeshGrpcEndpoints fails the build MeshGrpcMapConventionTests - source-scan of Program.cs (solution-root walk, following FlushLoggingConventionTests.cs's idiom): zero direct MapGrpcService +/// R3-01 T7 — a source-scan guard, following the solution-root-walk idiom +/// ZB.MOM.WW.OtOpcUa.Driver.S7.Cli.Tests.FlushLoggingConventionTests uses. Complements the +/// endpoint-metadata census (MeshGrpcAnonymousMetadataTests): the census catches a map +/// added to MeshGrpcEndpoints without the AllowAnonymous convention, but it cannot +/// catch a map added to Program.cs that bypasses the helper entirely — that shape never +/// goes through MapOtOpcUaMeshGrpcServices at all, so the census would simply never see it. +/// +/// +/// Would have FAILED at HEAD before T1: Program.cs used to carry the five map sites +/// inline (MapZbLocalDbSync(), four MapGrpcService<T>() calls) with no +/// MapOtOpcUaMeshGrpcServices call at all. +/// +public sealed class MeshGrpcMapConventionTests +{ + private static readonly string ProgramCsPath = LocateProgramCs(); + + [Fact] + public void ProgramCs_ContainsNoDirectMeshGrpcMapSites_AndExactlyOneMapperCall() + { + var source = File.ReadAllText(ProgramCsPath); + + // Guard-of-the-guard: a bad path (an empty file, or one that never had the mapper in the + // first place) must not pass this test by finding nothing to count. + source.ShouldNotBeNullOrWhiteSpace(); + source.ShouldContain("MapOtOpcUaMeshGrpcServices("); + + CountOccurrences(source, "MapGrpcService<").ShouldBe(0, + "every MapGrpcService() call must live inside MeshGrpcEndpoints.MapOtOpcUaMeshGrpcServices, " + + "not inline in Program.cs (03/S14 — a map added outside the helper is invisible to the " + + "endpoint-metadata census)."); + CountOccurrences(source, "MapZbLocalDbSync(").ShouldBe(0, + "the LocalDb sync map must live inside MeshGrpcEndpoints.MapOtOpcUaMeshGrpcServices, not inline " + + "in Program.cs, for the same reason as MapGrpcService() above."); + CountOccurrences(source, "MapOtOpcUaMeshGrpcServices(").ShouldBe(1, + "Program.cs must call the mapper exactly once; more than one call would map the mesh gRPC " + + "services twice (a route conflict) and zero calls would drop them entirely."); + } + + private static int CountOccurrences(string source, string needle) + { + var count = 0; + var index = 0; + while ((index = source.IndexOf(needle, index, StringComparison.Ordinal)) >= 0) + { + count++; + index += needle.Length; + } + + return count; + } + + private static string LocateProgramCs() + { + var dir = new DirectoryInfo(AppContext.BaseDirectory); + while (dir is not null && !File.Exists(Path.Combine(dir.FullName, "ZB.MOM.WW.OtOpcUa.slnx"))) + dir = dir.Parent; + dir.ShouldNotBeNull("Could not find solution root (ZB.MOM.WW.OtOpcUa.slnx)."); + return Path.Combine(dir!.FullName, "src", "Server", "ZB.MOM.WW.OtOpcUa.Host", "Program.cs"); + } +}