diff --git a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Cluster/CliRunner.Helpers.cs b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Cluster/CliRunner.Helpers.cs index 22146f07..16db7dbe 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Cluster/CliRunner.Helpers.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Cluster/CliRunner.Helpers.cs @@ -481,6 +481,22 @@ public static partial class CliRunner return RequireId(doc, "shared-script create"); } + /// + /// Creates an LDAP→role mapping via security role-mapping create and returns its new id. + /// + /// LDAP group name to map (typically from ). + /// Role to grant members of the group; defaults to Designer. + /// + /// The CLI failed, or the response did not carry an integer id. + /// + public static async Task CreateRoleMappingAsync(string ldapGroup, string role = "Designer") + { + using var doc = await RunJsonAsync( + "security", "role-mapping", "create", + "--ldap-group", ldapGroup, "--role", role); + return RequireId(doc, "security role-mapping create"); + } + /// /// Returns the ids of all external systems whose name starts with /// , via external-system list. Used to delete an @@ -514,6 +530,34 @@ public static partial class CliRunner /// Best-effort delete of a shared script via shared-script delete for teardown. public static Task DeleteSharedScriptAsync(int id) => BestEffortAsync("shared-script", "delete", id); + /// + /// Best-effort delete of an LDAP→role mapping via security role-mapping delete for teardown; + /// swallows any failure (the entity may already be gone). + /// + /// Role-mapping id. + /// + /// This method intentionally does NOT delegate to + /// even though the behaviour is identical. models + /// two-word commands (<group> <verb>), whereas + /// security role-mapping delete is a three-word command; extracting it would + /// require changing 's signature or adding an overload. + /// The inline try/catch is kept here deliberately — same pattern as + /// . + /// + public static async Task DeleteRoleMappingAsync(int id) + { + try + { + await RunAsync( + "security", "role-mapping", "delete", + "--id", id.ToString(System.Globalization.CultureInfo.InvariantCulture)); + } + catch + { + // Best-effort teardown — never mask the test's own failure. + } + } + /// /// Exports a Transport bundle scoped to a single template via /// bundle export. diff --git a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Cluster/CliRunnerHelpersTests.cs b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Cluster/CliRunnerHelpersTests.cs index 75d458ef..76793453 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Cluster/CliRunnerHelpersTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Cluster/CliRunnerHelpersTests.cs @@ -165,4 +165,27 @@ public class CliRunnerHelpersTests try { Assert.True(id > 0); } finally { await CliRunner.DeleteSharedScriptAsync(id); } } + + /// + /// A freshly created LDAP→role mapping returns a positive id, is discoverable by its + /// ldapGroupName in security role-mapping list, and is cleanly deleted in + /// teardown, exercising and + /// as a round-trip. + /// + [SkippableFact] + public async Task CreateThenDeleteRoleMapping_RoundTrips() + { + Skip.IfNot(await ClusterAvailability.IsAvailableAsync(), ClusterAvailability.SkipReason); + var group = CliRunner.UniqueName("grp"); + var id = await CliRunner.CreateRoleMappingAsync(group, "Designer"); + try + { + Assert.True(id > 0); + using var list = await CliRunner.RunJsonAsync("security", "role-mapping", "list"); + Assert.Contains( + list.RootElement.EnumerateArray(), + e => e.TryGetProperty("ldapGroupName", out var n) && n.GetString() == group); + } + finally { await CliRunner.DeleteRoleMappingAsync(id); } + } }