using Xunit; namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip.IntegrationTests; /// /// Runtime gate that lets an integration-test class declare which target-server tier /// it requires. Reads AB_SERVER_PROFILE from the environment; tests call /// with the profile names they support + skip otherwise. /// /// /// Two tiers today: /// /// abserver (default) — the Dockerized libplctag ab_server /// simulator. Covers atomic reads / writes / basic discovery across the four /// families (ControlLogix / CompactLogix / Micro800 / GuardLogix). /// emulate — Rockwell Studio 5000 Logix Emulate on an operator's /// Windows box, exposed via AB_SERVER_ENDPOINT. Adds real UDT / ALMD / /// AOI / Program-scoped-tag coverage that ab_server can't emulate. Tier-gated /// because Emulate is per-seat licensed + Windows-only + manually launched; /// a stock `dotnet test` run against ab_server must skip Emulate-only classes /// cleanly. /// /// Tests assert their target tier at the top of each [Fact] / /// [Theory] body, mirroring the MODBUS_SIM_PROFILE gate pattern in /// tests/.../Modbus.IntegrationTests/DL205/DL205StringQuirkTests.cs. /// public static class AbServerProfileGate { public const string Default = "abserver"; public const string Emulate = "emulate"; /// Active profile from AB_SERVER_PROFILE; defaults to . public static string CurrentProfile => Environment.GetEnvironmentVariable("AB_SERVER_PROFILE") is { Length: > 0 } raw ? raw.Trim().ToLowerInvariant() : Default; /// /// Skip the calling test via Assert.Skip when /// isn't in . Case-insensitive match. /// public static void SkipUnless(params string[] requiredProfiles) { foreach (var p in requiredProfiles) if (string.Equals(p, CurrentProfile, StringComparison.OrdinalIgnoreCase)) return; Assert.Skip( $"Test requires AB_SERVER_PROFILE in {{{string.Join(", ", requiredProfiles)}}}; " + $"current value is '{CurrentProfile}'. " + $"Set AB_SERVER_PROFILE=emulate + point AB_SERVER_ENDPOINT at a Logix Emulate instance to run the golden-box-tier tests."); } }