Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions src/Service.Tests/Configuration/HealthEndpointTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,94 @@ private static RuntimeConfig CreateRuntimeConfig(Dictionary<string, Entity> enti
return runtimeConfig;
}

/// <summary>
/// Verifies that stored procedures are excluded from health check results.
/// Creates a config with both a table entity and a stored procedure entity,
/// then validates that only the table entity appears in the health endpoint response.
/// </summary>
[TestMethod]
[TestCategory(TestCategory.MSSQL)]
public async Task HealthEndpoint_ExcludesStoredProcedures()
{
// Create a table entity
Entity tableEntity = new(
Health: new(enabled: true),
Source: new("books", EntitySourceType.Table, null, null),
Fields: null,
Rest: new(Enabled: true),
GraphQL: new("book", "bookLists", true),
Permissions: new[] { ConfigurationTests.GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) },
Relationships: null,
Mappings: null);

// Create a stored procedure entity
Entity storedProcEntity = new(
Health: new(enabled: true),
Source: new("GetData", EntitySourceType.StoredProcedure, null, null),
Fields: null,
Rest: new(Enabled: true),
GraphQL: new("getData", "getDataList", true),
Permissions: new[] { ConfigurationTests.GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) },
Relationships: null,
Mappings: null);

Dictionary<string, Entity> entityMap = new()
{
{ "Book", tableEntity },
{ "GetData", storedProcEntity }
};

RuntimeConfig runtimeConfig = CreateRuntimeConfig(
entityMap,
enableGlobalRest: true,
enableGlobalGraphql: true,
enabledGlobalMcp: true,
enableGlobalHealth: true,
enableDatasourceHealth: true,
hostMode: HostMode.Development);

WriteToCustomConfigFile(runtimeConfig);

string[] args = new[]
{
$"--ConfigFileName={CUSTOM_CONFIG_FILENAME}"
};

using (TestServer server = new(Program.CreateWebHostBuilder(args)))
using (HttpClient client = server.CreateClient())
{
HttpRequestMessage healthRequest = new(HttpMethod.Get, $"{BASE_DAB_URL}/health");
HttpResponseMessage response = await client.SendAsync(healthRequest);

Assert.AreEqual(HttpStatusCode.OK, response.StatusCode, "Health endpoint should return OK");

string responseBody = await response.Content.ReadAsStringAsync();
Dictionary<string, JsonElement> responseProperties = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(responseBody);

// Get the checks array
Assert.IsTrue(responseProperties.TryGetValue("checks", out JsonElement checksElement), "Response should contain 'checks' property");
Assert.AreEqual(JsonValueKind.Array, checksElement.ValueKind, "Checks should be an array");

// Get all entity names from the health check results
List<string> entityNamesInHealthCheck = new();
foreach (JsonElement check in checksElement.EnumerateArray())
{
if (check.TryGetProperty("name", out JsonElement nameElement))
{
entityNamesInHealthCheck.Add(nameElement.GetString());
}
}

// Verify that the table entity (Book) appears in health checks
Assert.IsTrue(entityNamesInHealthCheck.Contains("Book"),
"Table entity 'Book' should be included in health check results");

// Verify that the stored procedure entity (GetData) does NOT appear in health checks
Assert.IsFalse(entityNamesInHealthCheck.Contains("GetData"),
"Stored procedure entity 'GetData' should be excluded from health check results");
}
}

private static void WriteToCustomConfigFile(RuntimeConfig runtimeConfig)
{
File.WriteAllText(
Expand Down
3 changes: 2 additions & 1 deletion src/Service/HealthCheck/HealthCheckHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,10 +199,11 @@ private async Task UpdateDataSourceHealthCheckResultsAsync(ComprehensiveHealthCh

// Updates the Entity Health Check Results in the response.
// Goes through the entities one by one and executes the rest and graphql checks (if enabled).
// Stored procedures are excluded from health checks because they require parameters and are not guaranteed to be deterministic.
private async Task UpdateEntityHealthCheckResultsAsync(ComprehensiveHealthCheckReport report, RuntimeConfig runtimeConfig)
{
List<KeyValuePair<string, Entity>> enabledEntities = runtimeConfig.Entities.Entities
.Where(e => e.Value.IsEntityHealthEnabled)
.Where(e => e.Value.IsEntityHealthEnabled && e.Value.Source.Type != EntitySourceType.StoredProcedure)
.ToList();

if (enabledEntities.Count == 0)
Expand Down
Loading