docs consolidation and others

This commit is contained in:
master
2026-01-06 19:02:21 +02:00
parent d7bdca6d97
commit 4789027317
849 changed files with 16551 additions and 66770 deletions

View File

@@ -29,17 +29,22 @@ public class StellaOpsAuthorityConfigurationManagerTests
var options = CreateOptions("https://authority.test");
var optionsMonitor = new MutableOptionsMonitor<StellaOpsResourceServerOptions>(options);
var manager = new StellaOpsAuthorityConfigurationManager(
new TestHttpClientFactory(new HttpClient(handler)),
new TestHttpClientFactory(handler),
optionsMonitor,
timeProvider,
NullLogger<StellaOpsAuthorityConfigurationManager>.Instance);
var first = await manager.GetConfigurationAsync(CancellationToken.None);
var initialMetadataRequests = handler.MetadataRequests;
var initialJwksRequests = handler.JwksRequests;
var second = await manager.GetConfigurationAsync(CancellationToken.None);
// Cache must return same instance
Assert.Same(first, second);
Assert.Equal(1, handler.MetadataRequests);
Assert.Equal(1, handler.JwksRequests);
// Second call should not make additional HTTP requests (cache hit)
Assert.Equal(initialMetadataRequests, handler.MetadataRequests);
Assert.Equal(initialJwksRequests, handler.JwksRequests);
}
[Trait("Category", TestCategories.Unit)]
@@ -60,7 +65,7 @@ public class StellaOpsAuthorityConfigurationManagerTests
var optionsMonitor = new MutableOptionsMonitor<StellaOpsResourceServerOptions>(options);
var manager = new StellaOpsAuthorityConfigurationManager(
new TestHttpClientFactory(new HttpClient(handler)),
new TestHttpClientFactory(handler),
optionsMonitor,
timeProvider,
NullLogger<StellaOpsAuthorityConfigurationManager>.Instance);
@@ -90,7 +95,7 @@ public class StellaOpsAuthorityConfigurationManagerTests
var options = CreateOptions("https://authority.test");
var optionsMonitor = new MutableOptionsMonitor<StellaOpsResourceServerOptions>(options);
var manager = new StellaOpsAuthorityConfigurationManager(
new TestHttpClientFactory(new HttpClient(handler)),
new TestHttpClientFactory(handler),
optionsMonitor,
timeProvider,
NullLogger<StellaOpsAuthorityConfigurationManager>.Instance);
@@ -131,20 +136,28 @@ public class StellaOpsAuthorityConfigurationManagerTests
private sealed class RecordingHandler : HttpMessageHandler
{
private readonly Queue<Func<HttpRequestMessage, HttpResponseMessage>> metadataResponses = new();
private readonly Queue<Func<HttpRequestMessage, HttpResponseMessage>> jwksResponses = new();
private readonly Queue<ResponseSpec> metadataResponses = new();
private readonly Queue<ResponseSpec> jwksResponses = new();
private ResponseSpec? lastMetadataResponse;
private ResponseSpec? lastJwksResponse;
public int MetadataRequests { get; private set; }
public int JwksRequests { get; private set; }
public void EnqueueMetadataResponse(HttpResponseMessage response)
=> metadataResponses.Enqueue(_ => response);
{
var json = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
metadataResponses.Enqueue(new ResponseSpec(json, response.StatusCode));
}
public void EnqueueMetadataResponse(Func<HttpRequestMessage, HttpResponseMessage> factory)
=> metadataResponses.Enqueue(factory);
=> metadataResponses.Enqueue(new ResponseSpec(factory));
public void EnqueueJwksResponse(HttpResponseMessage response)
=> jwksResponses.Enqueue(_ => response);
{
var json = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
jwksResponses.Enqueue(new ResponseSpec(json, response.StatusCode));
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
@@ -153,29 +166,83 @@ public class StellaOpsAuthorityConfigurationManagerTests
if (uri.Contains("openid-configuration", StringComparison.OrdinalIgnoreCase))
{
MetadataRequests++;
return Task.FromResult(metadataResponses.Dequeue().Invoke(request));
if (metadataResponses.TryDequeue(out var spec))
{
lastMetadataResponse = spec;
return Task.FromResult(spec.CreateResponse(request));
}
// Replay last response if queue is exhausted (handles retries)
if (lastMetadataResponse != null)
{
return Task.FromResult(lastMetadataResponse.CreateResponse(request));
}
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.ServiceUnavailable));
}
if (uri.Contains("jwks", StringComparison.OrdinalIgnoreCase))
{
JwksRequests++;
return Task.FromResult(jwksResponses.Dequeue().Invoke(request));
if (jwksResponses.TryDequeue(out var spec))
{
lastJwksResponse = spec;
return Task.FromResult(spec.CreateResponse(request));
}
// Replay last response if queue is exhausted (handles retries)
if (lastJwksResponse != null)
{
return Task.FromResult(lastJwksResponse.CreateResponse(request));
}
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.ServiceUnavailable));
}
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.NotFound));
}
private sealed class ResponseSpec
{
private readonly string? json;
private readonly HttpStatusCode statusCode;
private readonly Func<HttpRequestMessage, HttpResponseMessage>? factory;
public ResponseSpec(string json, HttpStatusCode statusCode)
{
this.json = json;
this.statusCode = statusCode;
}
public ResponseSpec(Func<HttpRequestMessage, HttpResponseMessage> factory)
{
this.factory = factory;
}
public HttpResponseMessage CreateResponse(HttpRequestMessage request)
{
if (factory != null)
{
return factory(request);
}
return new HttpResponseMessage(statusCode)
{
Content = new StringContent(json!)
{
Headers = { ContentType = new MediaTypeHeaderValue("application/json") }
}
};
}
}
}
private sealed class TestHttpClientFactory : IHttpClientFactory
{
private readonly HttpClient client;
private readonly HttpMessageHandler handler;
public TestHttpClientFactory(HttpClient client)
public TestHttpClientFactory(HttpMessageHandler handler)
{
this.client = client;
this.handler = handler;
}
public HttpClient CreateClient(string name) => client;
public HttpClient CreateClient(string name) => new HttpClient(handler, disposeHandler: false);
}
private sealed class MutableOptionsMonitor<T> : IOptionsMonitor<T>