using GmRelay.Web.Health; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Npgsql; using System.Net; using System.Text.Json; namespace GmRelay.Bot.Tests.Web; public sealed class WebHealthEndpointTests { private static WebApplication CreateTestApp(HealthStatus npgsqlStatus) { var builder = WebApplication.CreateBuilder(); builder.WebHost.UseTestServer(); builder.Services.AddHealthChecks() .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]) .AddCheck("npgsql", () => new HealthCheckResult(npgsqlStatus)); var app = builder.Build(); app.MapHealthChecks("/health", new HealthCheckOptions { ResponseWriter = async (context, report) => { context.Response.ContentType = "application/json"; var response = new { status = report.Status == HealthStatus.Healthy ? "healthy" : "unhealthy", timestamp = DateTimeOffset.UtcNow.ToString("O") }; await context.Response.WriteAsJsonAsync(response); } }); app.MapHealthChecks("/alive", new HealthCheckOptions { Predicate = r => r.Tags.Contains("live") }); return app; } [Fact] public async Task HealthEndpoint_ShouldReturn200AndJson_WhenHealthy() { await using var app = CreateTestApp(HealthStatus.Healthy); await app.StartAsync(); using var client = app.GetTestClient(); var response = await client.GetAsync("/health"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); var content = await response.Content.ReadAsStringAsync(); using var doc = JsonDocument.Parse(content); Assert.Equal("healthy", doc.RootElement.GetProperty("status").GetString()); Assert.NotNull(doc.RootElement.GetProperty("timestamp").GetString()); } [Fact] public async Task HealthEndpoint_ShouldReturn503_WhenDatabaseUnavailable() { await using var app = CreateTestApp(HealthStatus.Unhealthy); await app.StartAsync(); using var client = app.GetTestClient(); var response = await client.GetAsync("/health"); Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode); } [Fact] public async Task NpgsqlHealthCheck_ShouldReturnUnhealthy_WhenDatabaseIsInaccessible() { var dataSource = NpgsqlDataSource.Create("Host=localhost;Port=5432;Database=gmrelay_db;Username=gmrelay;Password=fake"); var healthCheck = new NpgsqlHealthCheck(dataSource); var result = await healthCheck.CheckHealthAsync(new HealthCheckContext()); Assert.Equal(HealthStatus.Unhealthy, result.Status); Assert.NotNull(result.Exception); } }