feat: finish the host-metrics plugin, move host status into core (B16)

This commit is contained in:
LukeGus committed 2026-09-24 11:21:23 -05:00
1 parent 14eb558b85
commit 0a3f05d99d
308 files changed
+53073 -8985

No files matched your search

+109
View File
@@ -0,0 +1,109 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
const remoteCoreApiMock = vi.hoisted(() => ({ get: vi.fn() }));
const sshHostApiMock = vi.hoisted(() => ({
get: vi.fn(),
post: vi.fn(),
put: vi.fn(),
}));
const resolveConnectionOriginMock = vi.hoisted(() => vi.fn());
vi.mock("@/main-axios", () => ({
sshHostApi: sshHostApiMock,
getRemoteCoreApi: () => remoteCoreApiMock,
isElectron: () => true,
handleApiError: vi.fn(),
}));
vi.mock("@/lib/hosts-request-cache", () => ({
getCachedServerStatuses: (loader: () => Promise<unknown>) => loader(),
}));
vi.mock("@/lib/connection-origin", () => ({
resolveConnectionOrigin: resolveConnectionOriginMock,
}));
import {
getAllServerStatuses,
refreshServerPolling,
updateStatusCheckSettings,
} from "@/api/host-status-api";
/** The host list for "/db/host", core's statuses for "/status". */
function hostsAndStatuses(hosts: unknown[]) {
sshHostApiMock.get.mockImplementation(async (path: string) =>
path === "/status"
? { data: { 1: { status: "online" } } }
: { data: hosts },
);
}
beforeEach(() => {
vi.clearAllMocks();
window.electronAPI = {
invoke: vi.fn(async (channel: string) =>
channel === "get-remote-sync-config"
? { serverUrl: "https://termix.example.test" }
: null,
),
} as unknown as NonNullable<typeof window.electronAPI>;
remoteCoreApiMock.get.mockResolvedValue({
data: { 2: { status: "reachable" } },
});
});
describe("status check origin routing", () => {
it("only asks the embedded backend to poll local-origin hosts", async () => {
hostsAndStatuses([
{ id: 1, connectionOrigin: "local" },
{ id: 2, connectionOrigin: "remote" },
]);
resolveConnectionOriginMock.mockImplementation(async (host) =>
host.connectionOrigin === "local" ? "local" : "remote",
);
await expect(getAllServerStatuses()).resolves.toEqual({
1: { status: "online" },
2: { status: "reachable" },
});
expect(sshHostApiMock.get).toHaveBeenCalledWith("/status", {
timeout: 2000,
params: { hostIds: "1" },
__silentRetry: true,
});
expect(remoteCoreApiMock.get).toHaveBeenCalledWith(
"/host/status",
expect.objectContaining({ __silentRetry: true }),
);
});
it("sends an empty allowlist when every host uses the remote server", async () => {
hostsAndStatuses([{ id: 2, connectionOrigin: "remote" }]);
resolveConnectionOriginMock.mockResolvedValue("remote");
await getAllServerStatuses();
expect(sshHostApiMock.get).toHaveBeenCalledWith("/status", {
timeout: 2000,
params: { hostIds: "" },
__silentRetry: true,
});
});
});
describe("status check routes", () => {
it("restarts checks through core", async () => {
sshHostApiMock.post.mockResolvedValue({ data: {} });
await refreshServerPolling();
expect(sshHostApiMock.post).toHaveBeenCalledWith("/status/refresh");
});
it("saves the default interval", async () => {
sshHostApiMock.put.mockResolvedValue({ data: {} });
await updateStatusCheckSettings({ statusCheckInterval: 45 });
expect(sshHostApiMock.put).toHaveBeenCalledWith("/status/settings", {
statusCheckInterval: 45,
});
});
});
+2 -14
View File
@@ -23,13 +23,7 @@ describe("HostStatusCard", () => {
online: false,
} as Host;
render(
<HostStatusCard
hosts={[host]}
hostMetrics={new Map()}
onOpenTab={() => {}}
/>,
);
render(<HostStatusCard hosts={[host]} onOpenTab={() => {}} />);
const name = screen.getByText(host.name);
const ip = screen.getByText(host.ip);
@@ -90,13 +84,7 @@ describe("dashboard host routing", () => {
...flags,
} as unknown as Host;
const onOpenTab = vi.fn();
render(
<HostStatusCard
hosts={[host]}
hostMetrics={new Map()}
onOpenTab={onOpenTab}
/>,
);
render(<HostStatusCard hosts={[host]} onOpenTab={onOpenTab} />);
fireEvent.click(screen.getByText("Remote host"));
expect(onOpenTab).toHaveBeenCalledWith(host, expected);
});