w4c-workflows-api/w4c-workflows-api.Tests/WorkflowQuotaControllerTests.cs

91 lines
3.3 KiB
C#
Raw Normal View History

2026-09-13 16:28:47 +00:00
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using w4c_workflows.Controllers;
using w4c_workflows.Data;
using w4c_workflows.Services.Quota;
using Xunit;
namespace w4c_workflows.Tests;
/// <summary>
/// P1-14: resetting a tenant's monthly execution counter is a platform-admin
/// action. A tenant must not be able to zero its own quota, and the gate must
/// fail closed when <c>Workflows:AdminApiKey</c> is not configured at all.
/// </summary>
[Collection("WorkflowsPostgres")]
public class WorkflowQuotaControllerTests
{
private readonly WorkflowsPostgresFixture _fixture;
public WorkflowQuotaControllerTests(WorkflowsPostgresFixture fixture) => _fixture = fixture;
private static string Tenant() => "q" + Guid.NewGuid().ToString("N")[..12];
private static IConfiguration Config(string? adminKey)
=> new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>
{
["Workflows:AdminApiKey"] = adminKey,
})
.Build();
private static WorkflowQuotaController Controller(
WorkflowQuotaService quota, string tenantId, string? adminKey, string? providedKey)
{
var http = new DefaultHttpContext();
http.Items["TenantId"] = tenantId;
if (providedKey != null)
http.Request.Headers["X-Admin-Key"] = providedKey;
return new WorkflowQuotaController(quota, Config(adminKey))
{
ControllerContext = new ControllerContext { HttpContext = http },
};
}
[Fact]
public async Task Reset_is_forbidden_when_no_admin_key_is_configured()
{
var tenantId = Tenant();
await using var db = _fixture.CreateContext();
var result = await Controller(
QuotaTestData.Service(db), tenantId, adminKey: null, providedKey: "anything").Reset(default);
var forbidden = Assert.IsType<ObjectResult>(result);
Assert.Equal(StatusCodes.Status403Forbidden, forbidden.StatusCode);
}
[Fact]
public async Task Reset_is_forbidden_with_the_wrong_admin_key()
{
var tenantId = Tenant();
await using var db = _fixture.CreateContext();
var result = await Controller(
QuotaTestData.Service(db), tenantId, adminKey: "correct-secret", providedKey: "wrong-secret")
.Reset(default);
var forbidden = Assert.IsType<ObjectResult>(result);
Assert.Equal(StatusCodes.Status403Forbidden, forbidden.StatusCode);
}
[Fact]
public async Task Reset_with_the_admin_key_zeroes_the_counter()
{
var tenantId = Tenant();
await using var db = _fixture.CreateContext();
var quota = QuotaTestData.Service(db, new WorkflowQuotaOptions { RunsPerMonth = 10 });
Assert.True(await quota.TryReserveAsync(tenantId));
Assert.Equal(1, (await quota.GetAsync(tenantId)).Used);
var controller = Controller(quota, tenantId, adminKey: "correct-secret", providedKey: "correct-secret");
var result = Assert.IsType<OkObjectResult>(await controller.Reset(default));
var snapshot = Assert.IsType<WorkflowQuota>(result.Value);
Assert.Equal(0, snapshot.Used);
Assert.Equal(0, (await quota.GetAsync(tenantId)).Used);
}
}