feat(health-check): enhance HTTP probe functionality with URL helpers
Build and Push CFDM Docker Image / build-and-push (push) Successful in 1m51s
Build and Push CFDM Docker Image / create-release (push) Skipped
Build and Push CFDM Docker Image / update-wiki (push) Successful in 5s

Added new utility functions `hostForUrl` and `buildHttpProbeUrl` to improve URL construction for health checks. Updated `httpProbe` to utilize these functions, ensuring proper handling of FQDN and IP addresses. Enhanced tests to validate the new URL building logic and ensure correct behavior with different hostnames and IPs.
This commit is contained in:
Denozordec
2026-07-20 03:41:55 +07:00
parent 9d8c2aff86
commit a58d91ff5e
2 changed files with 122 additions and 15 deletions
+62 -1
View File
@@ -1,5 +1,6 @@
import { describe, expect, it, beforeAll, afterAll } from "vitest";
import { createServer, type Server } from "node:net";
import { createServer as createHttpServer, type Server as HttpServer } from "node:http";
import * as healthCheckService from "../src/services/health-check-service.js";
import type { HealthCheckTarget } from "@cfdm/shared";
@@ -15,6 +16,20 @@ function startTcpServer(): Promise<{ server: Server; port: number }> {
});
}
describe("health-check URL helpers", () => {
it("buildHttpProbeUrl uses FQDN in URL (IP pinned via DNS interceptor)", () => {
expect(
healthCheckService.buildHttpProbeUrl("gt.rkns.top", 443, "/", true),
).toBe("https://gt.rkns.top/");
expect(
healthCheckService.buildHttpProbeUrl("gt.rkns.top", 8080, "/health", false),
).toBe("http://gt.rkns.top:8080/health");
expect(
healthCheckService.buildHttpProbeUrl("2001:db8::1", 443, "/", true),
).toBe("https://[2001:db8::1]/");
});
});
describe("health-check probeTarget", () => {
let server: Server;
let port: number;
@@ -63,6 +78,53 @@ describe("health-check probeTarget", () => {
expect(result.ok).toBe(false);
expect(result.error).not.toBeNull();
});
it("http probe hits IP with Host=hostname (same IP, different FQDN)", async () => {
let seenHost: string | undefined;
const httpServer: HttpServer = createHttpServer((req, res) => {
seenHost = req.headers.host;
res.writeHead(200);
res.end("ok");
});
const httpPort = await new Promise<number>((resolve) => {
httpServer.listen(0, "127.0.0.1", () => {
const address = httpServer.address();
resolve(typeof address === "object" && address ? address.port : 0);
});
});
try {
const groupTarget: HealthCheckTarget = {
scope: "group",
ref_id: 1,
ip: "127.0.0.1",
hostname: "gt.rkns.top",
type: "http",
port: httpPort,
path: "/",
expected_status: 200,
timeout_ms: 1000,
};
const bindingTarget: HealthCheckTarget = {
...groupTarget,
scope: "binding",
hostname: "rutg.rkns.top",
};
const groupResult = await healthCheckService.probeTarget(groupTarget);
expect(groupResult.ok).toBe(true);
expect(seenHost?.startsWith("gt.rkns.top")).toBe(true);
const bindingResult = await healthCheckService.probeTarget(bindingTarget);
expect(bindingResult.ok).toBe(true);
expect(seenHost?.startsWith("rutg.rkns.top")).toBe(true);
// Same loopback IP → latencies in the same ballpark (not ~1s DNS skew)
expect(Math.abs(groupResult.latencyMs - bindingResult.latencyMs)).toBeLessThan(200);
} finally {
await new Promise<void>((resolve) => httpServer.close(() => resolve()));
}
});
});
describe("health-check state derivation via runAllChecks", () => {
@@ -90,7 +152,6 @@ describe("health-check state derivation via runAllChecks", () => {
{ ip: "127.0.0.1", weight: 1, priority: 1 },
]);
// Запуск с closed port (port 1) — должен зафиксировать down после 2 проверок
await healthCheckService.runAllChecks(db, {
thresholds: {
degradedFailures: 1,