feat(health-check): enhance HTTP probe functionality with URL helpers
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:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user