import type { Client } from "ssh2"; import { describe, it, expect, vi } from "vitest"; import { supportsMetrics, isTcpPingEnabled, createConnectionLog, tcpPingThroughJumpHost, } from "./host-metrics-helpers.js"; describe("supportsMetrics", () => { it("supports plain ssh hosts", () => { expect( supportsMetrics({ connectionType: "ssh", authType: "password" }), ).toBe(true); }); it("defaults missing connectionType to ssh", () => { expect(supportsMetrics({ authType: "key" })).toBe(true); }); it("rejects non-ssh connection types", () => { expect(supportsMetrics({ connectionType: "rdp" })).toBe(false); expect(supportsMetrics({ connectionType: "vnc" })).toBe(false); expect(supportsMetrics({ connectionType: "telnet" })).toBe(false); }); it("rejects ssh hosts that cannot run shell commands", () => { expect(supportsMetrics({ connectionType: "ssh", authType: "none" })).toBe( false, ); expect(supportsMetrics({ connectionType: "ssh", authType: "opkssh" })).toBe( false, ); }); }); describe("isTcpPingEnabled", () => { it("is enabled when status checks are on and tcp ping is not disabled", () => { expect( isTcpPingEnabled({ statusCheckEnabled: true, disableTcpPing: false }), ).toBe(true); expect(isTcpPingEnabled({ statusCheckEnabled: true })).toBe(true); }); it("is disabled when status checks are off", () => { expect(isTcpPingEnabled({ statusCheckEnabled: false })).toBe(false); }); it("is disabled when tcp ping is explicitly disabled", () => { expect( isTcpPingEnabled({ statusCheckEnabled: true, disableTcpPing: true }), ).toBe(false); }); }); describe("createConnectionLog", () => { it("builds a log entry without id/timestamp", () => { const entry = createConnectionLog("info", "connection", "Connecting", { hostId: 1, }); expect(entry).toEqual({ type: "info", stage: "connection", message: "Connecting", details: { hostId: 1 }, }); expect("id" in entry).toBe(false); expect("timestamp" in entry).toBe(false); }); }); describe("tcpPingThroughJumpHost", () => { it("reports the final destination online when forwarding succeeds", async () => { const stream = { destroy: vi.fn() }; const jumpClient = { end: vi.fn(), forwardOut: vi.fn((_src, _srcPort, host, port, callback) => { expect(host).toBe("private.example"); expect(port).toBe(22); callback(undefined, stream); }), } as unknown as Pick; await expect( tcpPingThroughJumpHost(jumpClient, "private.example", 22), ).resolves.toBe(true); expect(stream.destroy).toHaveBeenCalledOnce(); expect(jumpClient.end).toHaveBeenCalledOnce(); }); it("reports the final destination offline when forwarding fails", async () => { const jumpClient = { end: vi.fn(), forwardOut: vi.fn((_src, _srcPort, _host, _port, callback) => { callback(new Error("Connection refused")); }), } as unknown as Pick; await expect( tcpPingThroughJumpHost(jumpClient, "private.example", 22), ).resolves.toBe(false); expect(jumpClient.end).toHaveBeenCalledOnce(); }); it("reports the final destination offline when forwarding times out", async () => { vi.useFakeTimers(); const jumpClient = { end: vi.fn(), forwardOut: vi.fn(), } as unknown as Pick; const result = tcpPingThroughJumpHost( jumpClient, "private.example", 22, 5000, ); await vi.advanceTimersByTimeAsync(5000); await expect(result).resolves.toBe(false); expect(jumpClient.end).toHaveBeenCalledOnce(); vi.useRealTimers(); }); });