using System.Net.Http.Json;
using System.Text.Json.Serialization;
namespace Azaion.Missions.E2E.Fixtures;
///
/// Triggers POST {jwks-mock}/rotate-key and waits up to
/// RotationTimeout for the missions service to refresh its JWKS cache,
/// observable via successful authentication with the new kid.
///
public sealed class JwksRotateFixture
{
public TimeSpan RotationTimeout { get; init; } = TimeSpan.FromSeconds(45);
public async Task RotateAndWaitAsync(
Func> isNewKeyAccepted,
CancellationToken ct = default)
{
var rotateUrl = new Uri(new Uri(TestEnvironment.JwksMockBaseUrl), "/rotate-key");
using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(10) };
using var resp = await http.PostAsync(rotateUrl, content: null, ct).ConfigureAwait(false);
resp.EnsureSuccessStatusCode();
var rotated = await resp.Content.ReadFromJsonAsync(cancellationToken: ct).ConfigureAwait(false);
if (rotated is null)
throw new InvalidOperationException("jwks-mock /rotate-key returned an empty body");
var deadline = DateTime.UtcNow + RotationTimeout;
while (DateTime.UtcNow < deadline)
{
if (await isNewKeyAccepted().ConfigureAwait(false))
return new RotationResult(rotated.Kid, Accepted: true);
await Task.Delay(TimeSpan.FromMilliseconds(500), ct).ConfigureAwait(false);
}
return new RotationResult(rotated.Kid, Accepted: false);
}
public sealed record RotationResult(string NewKid, bool Accepted);
private sealed record RotateResponse(
[property: JsonPropertyName("kid")] string Kid);
}