using Xunit; namespace ZB.MOM.WW.OtOpcUa.Cluster.Tests; /// Sets an environment variable for the scope's lifetime and restores its prior value on dispose. public sealed class EnvVarScope : IDisposable { private readonly string _name; private readonly string? _previous; /// Sets to until disposed. /// The environment variable name. /// The value to set, or null to unset. public EnvVarScope(string name, string? value) { _name = name; _previous = Environment.GetEnvironmentVariable(name); Environment.SetEnvironmentVariable(name, value); } /// public void Dispose() => Environment.SetEnvironmentVariable(_name, _previous); } /// /// Serializes every test class that reads or writes the OTOPCUA_ROLES process environment. /// /// /// ⚠️ Load-bearing since Gitea #532. Environment variables are process-global while xUnit runs /// test classes in an assembly concurrently, so a class that sets OTOPCUA_ROLES is /// visible to every class running beside it. That was harmless while /// SplitTopologyTransportValidator was the only code applying the fallback — its own tests both /// set and read the variable. It stopped being harmless when ConfigSourceOptionsValidator and /// TelemetryOptionsValidator started resolving effective roles the same way: their cases that /// pass NO roles would intermittently observe another class's driver,cluster-SITE-A and change /// verdict. Any test touching that variable, directly or through /// RoleParser.ResolveEffectiveRoles, belongs in this collection. /// [CollectionDefinition(Name, DisableParallelization = true)] public sealed class RoleEnvironmentCollection { /// The collection name to put on [Collection]. public const string Name = "role-environment"; }