diff --git a/src/Service.Tests/Configuration/HotReload/ConfigurationHotReloadTests.cs b/src/Service.Tests/Configuration/HotReload/ConfigurationHotReloadTests.cs index 18c19cbd7a..05a858a654 100644 --- a/src/Service.Tests/Configuration/HotReload/ConfigurationHotReloadTests.cs +++ b/src/Service.Tests/Configuration/HotReload/ConfigurationHotReloadTests.cs @@ -780,12 +780,28 @@ await WaitForConditionAsync( succeedConfigLog = _writer.ToString(); } - HttpResponseMessage restResult = await _testClient.GetAsync("/rest/Book"); + // Retry REST request because metadata re-initialization happens asynchronously + // after the "Validated hot-reloaded configuration file" message. The metadata provider + // factory clears and re-initializes providers on the hot-reload thread, so requests + // arriving before that completes will fail. + HttpResponseMessage restResult = null; + bool restSucceeded = false; + for (int attempt = 1; attempt <= 10; attempt++) + { + restResult = await _testClient.GetAsync("/rest/Book"); + if (restResult.StatusCode == HttpStatusCode.OK) + { + restSucceeded = true; + break; + } + + await Task.Delay(1000); + } // Assert Assert.IsTrue(failedConfigLog.Contains(HOT_RELOAD_FAILURE_MESSAGE)); Assert.IsTrue(succeedConfigLog.Contains(HOT_RELOAD_SUCCESS_MESSAGE)); - Assert.AreEqual(HttpStatusCode.OK, restResult.StatusCode); + Assert.IsTrue(restSucceeded, $"REST request did not return OK after hot-reload. Last status: {restResult?.StatusCode}"); } /// @@ -838,12 +854,28 @@ await WaitForConditionAsync( succeedConfigLog = _writer.ToString(); } - HttpResponseMessage restResult = await _testClient.GetAsync("/rest/Book"); + // Retry REST request because metadata re-initialization happens asynchronously + // after the "Validated hot-reloaded configuration file" message. The metadata provider + // factory clears and re-initializes providers on the hot-reload thread, so requests + // arriving before that completes will fail. + HttpResponseMessage restResult = null; + bool restSucceeded = false; + for (int attempt = 1; attempt <= 10; attempt++) + { + restResult = await _testClient.GetAsync("/rest/Book"); + if (restResult.StatusCode == HttpStatusCode.OK) + { + restSucceeded = true; + break; + } + + await Task.Delay(1000); + } // Assert Assert.IsTrue(failedConfigLog.Contains(HOT_RELOAD_FAILURE_MESSAGE)); Assert.IsTrue(succeedConfigLog.Contains(HOT_RELOAD_SUCCESS_MESSAGE)); - Assert.AreEqual(HttpStatusCode.OK, restResult.StatusCode); + Assert.IsTrue(restSucceeded, $"REST request did not return OK after hot-reload. Last status: {restResult?.StatusCode}"); } /// diff --git a/src/Service/HealthCheck/ComprehensiveHealthReportResponseWriter.cs b/src/Service/HealthCheck/ComprehensiveHealthReportResponseWriter.cs index 5027c5e059..26846e6b9c 100644 --- a/src/Service/HealthCheck/ComprehensiveHealthReportResponseWriter.cs +++ b/src/Service/HealthCheck/ComprehensiveHealthReportResponseWriter.cs @@ -109,7 +109,7 @@ public async Task WriteResponseAsync(HttpContext context) // Ensure cachedResponse is not null before calling WriteAsync if (report != null) { - // Set currentRole per-request (not cached) so each caller sees their own role + // Set current-role per-request (not cached) so each caller sees their own role await context.Response.WriteAsync(SerializeReport(report with { CurrentRole = _healthCheckHelper.GetCurrentRole(roleHeader, roleToken) })); } else diff --git a/src/Service/HealthCheck/Model/ComprehensiveHealthCheckReport.cs b/src/Service/HealthCheck/Model/ComprehensiveHealthCheckReport.cs index 26a260af47..a63c2debf2 100644 --- a/src/Service/HealthCheck/Model/ComprehensiveHealthCheckReport.cs +++ b/src/Service/HealthCheck/Model/ComprehensiveHealthCheckReport.cs @@ -46,7 +46,7 @@ public record ComprehensiveHealthCheckReport /// /// The current role of the user making the request (e.g., "anonymous", "authenticated"). /// - [JsonPropertyName("currentRole")] + [JsonPropertyName("current-role")] public string? CurrentRole { get; set; } ///