test(playwright): add CLI role-mapping create/delete helpers (Wave 4 prep)

This commit is contained in:
Joseph Doherty
2026-06-07 03:28:29 -04:00
parent 7fda67be9e
commit 40f6d21392
2 changed files with 67 additions and 0 deletions
@@ -481,6 +481,22 @@ public static partial class CliRunner
return RequireId(doc, "shared-script create");
}
/// <summary>
/// Creates an LDAP→role mapping via <c>security role-mapping create</c> and returns its new <c>id</c>.
/// </summary>
/// <param name="ldapGroup">LDAP group name to map (typically from <see cref="UniqueName"/>).</param>
/// <param name="role">Role to grant members of the group; defaults to <c>Designer</c>.</param>
/// <exception cref="InvalidOperationException">
/// The CLI failed, or the response did not carry an integer <c>id</c>.
/// </exception>
public static async Task<int> 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");
}
/// <summary>
/// Returns the ids of all external systems whose <c>name</c> starts with
/// <paramref name="prefix"/>, via <c>external-system list</c>. Used to delete an
@@ -514,6 +530,34 @@ public static partial class CliRunner
/// <summary>Best-effort delete of a shared script via <c>shared-script delete</c> for teardown.</summary>
public static Task DeleteSharedScriptAsync(int id) => BestEffortAsync("shared-script", "delete", id);
/// <summary>
/// Best-effort delete of an LDAP→role mapping via <c>security role-mapping delete</c> for teardown;
/// swallows any failure (the entity may already be gone).
/// </summary>
/// <param name="id">Role-mapping id.</param>
/// <remarks>
/// This method intentionally does NOT delegate to <see cref="BestEffortAsync"/>
/// even though the behaviour is identical. <see cref="BestEffortAsync"/> models
/// two-word commands (<c>&lt;group&gt; &lt;verb&gt;</c>), whereas
/// <c>security role-mapping delete</c> is a three-word command; extracting it would
/// require changing <see cref="BestEffortAsync"/>'s signature or adding an overload.
/// The inline try/catch is kept here deliberately — same pattern as
/// <see cref="DeleteAreaAsync"/>.
/// </remarks>
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.
}
}
/// <summary>
/// Exports a Transport bundle scoped to a single template via
/// <c>bundle export</c>.
@@ -165,4 +165,27 @@ public class CliRunnerHelpersTests
try { Assert.True(id > 0); }
finally { await CliRunner.DeleteSharedScriptAsync(id); }
}
/// <summary>
/// A freshly created LDAP→role mapping returns a positive id, is discoverable by its
/// <c>ldapGroupName</c> in <c>security role-mapping list</c>, and is cleanly deleted in
/// teardown, exercising <see cref="CliRunner.CreateRoleMappingAsync"/> and
/// <see cref="CliRunner.DeleteRoleMappingAsync"/> as a round-trip.
/// </summary>
[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); }
}
}