87ff00fd30
Phase 6 (per-cluster mesh split) needs nodes to carry a cluster-scoped role like cluster-SITE-A; RoleParser previously rejected anything outside the fixed admin/driver/dev set. Adds IsClusterRole/ ClusterIdFromRole plus well-known-role constants, and points the three duplicate "driver" string literals (RedundancyStateActor, ClusterNodeAddressReconcilerActor, ServiceCollectionExtensions) at the new RoleParser.Driver so the value has one source, without renaming any existing DriverRole symbol. Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW
114 lines
3.7 KiB
C#
114 lines
3.7 KiB
C#
using Shouldly;
|
|
using Xunit;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Cluster.Tests;
|
|
|
|
public sealed class RoleParserTests
|
|
{
|
|
/// <summary>Verifies that empty input yields an empty array.</summary>
|
|
/// <param name="raw">The raw input string to test (null, empty, or whitespace).</param>
|
|
[Theory]
|
|
[InlineData(null)]
|
|
[InlineData("")]
|
|
[InlineData(" ")]
|
|
public void Empty_input_yields_empty_array(string? raw)
|
|
{
|
|
RoleParser.Parse(raw).ShouldBeEmpty();
|
|
}
|
|
|
|
/// <summary>Verifies that a single role 'admin' is parsed correctly.</summary>
|
|
[Fact]
|
|
public void Single_role_admin()
|
|
{
|
|
RoleParser.Parse("admin").ShouldBe(new[] { "admin" });
|
|
}
|
|
|
|
/// <summary>Verifies that two roles separated by comma are parsed correctly.</summary>
|
|
[Fact]
|
|
public void Two_roles_csv()
|
|
{
|
|
RoleParser.Parse("admin,driver").ShouldBe(new[] { "admin", "driver" });
|
|
}
|
|
|
|
/// <summary>Verifies that parser tolerates surrounding whitespace.</summary>
|
|
[Fact]
|
|
public void Whitespace_tolerant()
|
|
{
|
|
RoleParser.Parse(" admin , driver ").ShouldBe(new[] { "admin", "driver" });
|
|
}
|
|
|
|
/// <summary>Verifies that parser is case-insensitive and normalizes to lowercase.</summary>
|
|
[Fact]
|
|
public void Case_insensitive_normalizes_to_lower()
|
|
{
|
|
RoleParser.Parse("ADMIN,Driver").ShouldBe(new[] { "admin", "driver" });
|
|
}
|
|
|
|
/// <summary>Verifies that duplicate roles are removed.</summary>
|
|
[Fact]
|
|
public void Duplicate_roles_deduped()
|
|
{
|
|
RoleParser.Parse("admin,admin,driver").ShouldBe(new[] { "admin", "driver" });
|
|
}
|
|
|
|
/// <summary>Verifies that parser throws for unknown roles.</summary>
|
|
[Fact]
|
|
public void Unknown_role_throws()
|
|
{
|
|
Should.Throw<ArgumentException>(() => RoleParser.Parse("admin,master"));
|
|
}
|
|
|
|
/// <summary>Verifies that a single cluster-scoped role is accepted.</summary>
|
|
[Theory]
|
|
[InlineData("cluster-MAIN")]
|
|
[InlineData("cluster-SITE-A")]
|
|
public void Cluster_role_accepted(string role)
|
|
{
|
|
RoleParser.Parse(role).ShouldBe(new[] { role.ToLowerInvariant() });
|
|
}
|
|
|
|
/// <summary>Verifies that cluster roles mix freely with the fixed roles.</summary>
|
|
[Fact]
|
|
public void Fixed_and_cluster_roles_mix()
|
|
{
|
|
RoleParser.Parse("driver,cluster-SITE-A").ShouldBe(new[] { "driver", "cluster-site-a" });
|
|
}
|
|
|
|
/// <summary>Verifies that a cluster role with an empty ClusterId ("cluster-") is rejected.</summary>
|
|
[Fact]
|
|
public void Empty_cluster_id_throws()
|
|
{
|
|
Should.Throw<ArgumentException>(() => RoleParser.Parse("cluster-"));
|
|
}
|
|
|
|
/// <summary>Verifies IsClusterRole returns true for valid cluster roles and false otherwise.</summary>
|
|
[Theory]
|
|
[InlineData("cluster-MAIN", true)]
|
|
[InlineData("cluster-SITE-A", true)]
|
|
[InlineData("cluster-", false)]
|
|
[InlineData("driver", false)]
|
|
[InlineData("admin", false)]
|
|
[InlineData("clusterx", false)]
|
|
public void IsClusterRole_classifies_correctly(string role, bool expected)
|
|
{
|
|
RoleParser.IsClusterRole(role).ShouldBe(expected);
|
|
}
|
|
|
|
/// <summary>Verifies ClusterIdFromRole extracts the ClusterId suffix.</summary>
|
|
[Fact]
|
|
public void ClusterIdFromRole_extracts_suffix()
|
|
{
|
|
RoleParser.ClusterIdFromRole("cluster-SITE-A").ShouldBe("SITE-A");
|
|
}
|
|
|
|
/// <summary>Verifies the three well-known role constants match the historical literal values.</summary>
|
|
[Fact]
|
|
public void Well_known_role_constants()
|
|
{
|
|
RoleParser.Admin.ShouldBe("admin");
|
|
RoleParser.Driver.ShouldBe("driver");
|
|
RoleParser.Dev.ShouldBe("dev");
|
|
RoleParser.ClusterRolePrefix.ShouldBe("cluster-");
|
|
}
|
|
}
|