shoc-backend/Api.SeaHavenIndustries.Tests/TeamMemberPermissionsEndpointTests.cs
Alexandre Brandizzi e09ef061d1 Merge remote-tracking branch 'origin/main' into feat/ab/sh-385-invite-registration
# Conflicts:
#	Api.SeaHavenIndustries/Controllers/TeamMemberController.cs
2026-09-25 12:45:03 -03:00

98 lines
4.2 KiB
C#

using Api.SeaHavenIndustries.Controllers;
using Data.SeaHavenIndustries.Enums;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using SeaHaven.DataServices.Dto;
using SeaHaven.DataServices.Interfaces;
using SeaHaven.Services.Constants;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Implementation;
using SeaHaven.Services.Interfaces;
using System.Security.Claims;
using System.Text.Json;
using Xunit;
namespace Api.SeaHavenIndustries.Tests;
public sealed class TeamMemberPermissionsEndpointTests
{
[Fact]
public async Task Signed_in_caller_receives_their_effective_keys_as_a_permissions_array()
{
var data = new Mock<ITeamPermissionOverrideDataService>();
data.Setup(d => d.GetUserAsync("u1", It.IsAny<CancellationToken>()))
.ReturnsAsync(new TeamPermissionUserData
{
UserId = "u1",
RoleName = "Dispatcher",
Overrides = new Dictionary<string, UserPermissionState>
{
[TeamPermissionKeys.CreateCompletionDocTemplates] = UserPermissionState.Allow
}
});
var controller = Controller(data.Object, new ClaimsPrincipal(new ClaimsIdentity(
new[] { new Claim(ClaimTypes.NameIdentifier, "u1") }, "Bearer")));
var ok = Assert.IsType<OkObjectResult>(await controller.GetMyPermissions(CancellationToken.None));
var json = JsonSerializer.Serialize(ok.Value, new JsonSerializerOptions(JsonSerializerDefaults.Web));
using var document = JsonDocument.Parse(json);
var keys = document.RootElement.GetProperty("permissions").EnumerateArray()
.Select(element => element.GetString()).ToList();
Assert.Contains(TeamPermissionKeys.CreateCompletionDocTemplates, keys);
Assert.DoesNotContain(TeamPermissionKeys.DeleteCompletionDocTemplates, keys);
}
[Fact]
public async Task Unauthenticated_caller_gets_401_without_data_access()
{
var data = new Mock<ITeamPermissionOverrideDataService>(MockBehavior.Strict);
var controller = Controller(data.Object, new ClaimsPrincipal(new ClaimsIdentity()));
var result = Assert.IsType<UnauthorizedResult>(await controller.GetMyPermissions(CancellationToken.None));
Assert.Equal(StatusCodes.Status401Unauthorized, result.StatusCode);
}
[Fact]
public void Route_is_get_me_permissions_and_requires_authentication()
{
var services = new ServiceCollection();
services.AddLogging();
services.AddMvcCore().AddApplicationPart(typeof(TeamMemberController).Assembly);
using var provider = services.BuildServiceProvider();
var descriptor = provider
.GetRequiredService<IActionDescriptorCollectionProvider>()
.ActionDescriptors.Items
.OfType<ControllerActionDescriptor>()
.Single(d => d.ControllerTypeInfo == typeof(TeamMemberController)
&& d.ActionName == nameof(TeamMemberController.GetMyPermissions));
var methods = descriptor.ActionConstraints!.OfType<HttpMethodActionConstraint>()
.SelectMany(c => c.HttpMethods);
Assert.Equal(new[] { "GET" }, methods);
Assert.Equal("api/team-members/me/permissions", descriptor.AttributeRouteInfo!.Template);
Assert.NotEmpty(typeof(TeamMemberController).GetCustomAttributes(typeof(AuthorizeAttribute), true));
Assert.Empty(descriptor.MethodInfo.GetCustomAttributes(typeof(AllowAnonymousAttribute), true));
}
private static TeamMemberController Controller(
ITeamPermissionOverrideDataService data,
ClaimsPrincipal user) =>
new(
Mock.Of<ITeamMemberService>(),
new TeamPermissionService(data, new TeamPermissionPolicy()),
Mock.Of<ITeamMemberInviteService>())
{
ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext { User = user }
}
};
}