feat(health): IActiveNodeGate seam + RequireActiveNode filter
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.TestHost;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ZB.MOM.WW.Health;
|
||||
|
||||
namespace ZB.MOM.WW.Health.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Verifies <see cref="ActiveNodeGateExtensions.RequireActiveNode"/>: a decorated endpoint serves
|
||||
/// normally (200) when the resolved <see cref="IActiveNodeGate"/> reports the node active, and
|
||||
/// returns 503 with a <c>Retry-After</c> header when the node is a standby.
|
||||
/// </summary>
|
||||
public sealed class ActiveNodeGateTests
|
||||
{
|
||||
private sealed class FakeActiveNodeGate : IActiveNodeGate
|
||||
{
|
||||
public bool IsActiveNode { get; set; }
|
||||
}
|
||||
|
||||
private static async Task<HttpResponseMessage> CallAsync(bool isActive)
|
||||
{
|
||||
var builder = WebApplication.CreateBuilder();
|
||||
builder.WebHost.UseTestServer();
|
||||
builder.Services.AddSingleton<IActiveNodeGate>(new FakeActiveNodeGate { IsActiveNode = isActive });
|
||||
|
||||
await using var app = builder.Build();
|
||||
app.MapGet("/x", () => "ok").RequireActiveNode();
|
||||
await app.StartAsync();
|
||||
|
||||
var client = app.GetTestClient();
|
||||
return await client.GetAsync("/x");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ActiveNode_Returns200()
|
||||
{
|
||||
var response = await CallAsync(isActive: true);
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("ok", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task StandbyNode_Returns503_WithRetryAfterHeader()
|
||||
{
|
||||
var response = await CallAsync(isActive: false);
|
||||
|
||||
Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode);
|
||||
Assert.True(
|
||||
response.Headers.Contains("Retry-After"),
|
||||
"Standby response must carry a Retry-After header.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task NoGateRegistered_AllowsRequest()
|
||||
{
|
||||
// When no IActiveNodeGate is registered (non-clustered host / tests), the endpoint is served.
|
||||
var builder = WebApplication.CreateBuilder();
|
||||
builder.WebHost.UseTestServer();
|
||||
|
||||
await using var app = builder.Build();
|
||||
app.MapGet("/x", () => "ok").RequireActiveNode();
|
||||
await app.StartAsync();
|
||||
|
||||
var response = await app.GetTestClient().GetAsync("/x");
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user