Files
lmxopcua/tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests/Audit/HttpAuditActorAccessorTests.cs
T
Joseph Doherty bd6c0b4d3d docs: complete XML doc comments via fixdocs (2757 to 131 findings)
Add missing <returns>/<param>/<summary>/<typeparam> tags and clean up
misused inheritdoc across 481 files so the documented API surface is
complete. Documentation-only (zero code lines changed). The 131 remaining
findings are inheritdoc-style warnings deliberately left to preserve
hand-written implementation rationale (plan-decision notes, race-condition
explanations).
2026-06-03 12:34:34 -04:00

117 lines
4.4 KiB
C#

using System.Security.Claims;
using Microsoft.AspNetCore.Http;
using Shouldly;
using Xunit;
using ZB.MOM.WW.Auth.AspNetCore;
using ZB.MOM.WW.OtOpcUa.Security.Audit;
namespace ZB.MOM.WW.OtOpcUa.Security.Tests.Audit;
/// <summary>
/// Unit tests for <see cref="HttpAuditActorAccessor"/>.
/// <para>
/// Covers the three cases:
/// <list type="bullet">
/// <item>Authenticated principal with a <see cref="ZbClaimTypes.Username"/> claim →
/// returns the username claim value.</item>
/// <item>Authenticated principal with only a <see cref="ZbClaimTypes.Name"/> / no
/// username claim → falls back to the Name claim.</item>
/// <item>No HTTP context (null) or unauthenticated principal → returns
/// <see langword="null"/>.</item>
/// </list>
/// </para>
/// </summary>
public sealed class HttpAuditActorAccessorTests
{
// ── helpers ──────────────────────────────────────────────────────────────────
private static IHttpContextAccessor ContextWith(ClaimsPrincipal principal)
{
var context = new DefaultHttpContext { User = principal };
return new HttpContextAccessorStub(context);
}
private static IHttpContextAccessor NoContext() =>
new HttpContextAccessorStub(null);
private static ClaimsPrincipal AuthenticatedWith(params Claim[] claims)
{
var identity = new ClaimsIdentity(
claims,
authenticationType: "TestScheme", // non-null authenticationType → IsAuthenticated = true
nameType: ZbClaimTypes.Name,
roleType: ZbClaimTypes.Role);
return new ClaimsPrincipal(identity);
}
private static ClaimsPrincipal Unauthenticated() =>
new(new ClaimsIdentity()); // no authenticationType → IsAuthenticated = false
// ── tests ─────────────────────────────────────────────────────────────────────
/// <summary>
/// An authenticated principal that carries <see cref="ZbClaimTypes.Username"/>
/// returns exactly that claim value — it is the canonical actor string.
/// </summary>
[Fact]
public void Returns_username_claim_for_authenticated_principal()
{
var principal = AuthenticatedWith(
new Claim(ZbClaimTypes.Username, "alice"),
new Claim(ZbClaimTypes.Name, "alice-name"),
new Claim(ZbClaimTypes.DisplayName, "Alice User"));
var sut = new HttpAuditActorAccessor(ContextWith(principal));
sut.CurrentActor.ShouldBe("alice");
}
/// <summary>
/// When the principal has no <see cref="ZbClaimTypes.Username"/> claim but does have
/// a <see cref="ZbClaimTypes.Name"/> claim, the Name claim value is returned as the
/// fallback actor.
/// </summary>
[Fact]
public void Falls_back_to_Name_claim_when_Username_claim_is_absent()
{
var principal = AuthenticatedWith(
new Claim(ZbClaimTypes.Name, "bob"));
var sut = new HttpAuditActorAccessor(ContextWith(principal));
sut.CurrentActor.ShouldBe("bob");
}
/// <summary>
/// An unauthenticated principal (Identity.IsAuthenticated == false) returns null —
/// the caller's fallback (typically <see cref="AuditActor.SystemFallback"/>) is used.
/// </summary>
[Fact]
public void Returns_null_for_unauthenticated_principal()
{
var sut = new HttpAuditActorAccessor(ContextWith(Unauthenticated()));
sut.CurrentActor.ShouldBeNull();
}
/// <summary>
/// When there is no current <c>HttpContext</c> (e.g. background task, actor mailbox
/// worker), returns null.
/// </summary>
[Fact]
public void Returns_null_when_no_HttpContext()
{
var sut = new HttpAuditActorAccessor(NoContext());
sut.CurrentActor.ShouldBeNull();
}
// ── stub ──────────────────────────────────────────────────────────────────────
private sealed class HttpContextAccessorStub(HttpContext? context) : IHttpContextAccessor
{
/// <summary>Gets or sets the HTTP context for the stub.</summary>
public HttpContext? HttpContext { get; set; } = context;
}
}