Files
Checkmate/server/test/unit/services/checkProducer.test.ts
T

213 lines
9.3 KiB
TypeScript
Raw Normal View History

2026-06-18 11:06:57 -07:00
import { describe, expect, it, jest } from "@jest/globals";
import { CheckProducer } from "../../../src/worker/worker.check-producer.ts";
2026-07-24 12:28:45 -07:00
import type { Monitor } from "../../../src/domain/monitors/monitor.type.ts";
2026-06-18 11:06:57 -07:00
import { createMockLogger } from "../../helpers/createMockLogger.ts";
const makeMonitor = (overrides?: Partial<Monitor>): Monitor =>
({
id: "m1",
teamId: "team",
type: "http",
interval: 60000,
status: "up",
...overrides,
}) as Monitor;
// A maintenance window straddling "now" — active per isWindowActive.
const activeWindow = () => {
const now = Date.now();
return { active: true, start: new Date(now - 1000).toISOString(), end: new Date(now + 1000).toISOString(), repeat: 0 };
};
const createProducer = (overrides?: Record<string, any>) => {
const defaults = {
logger: createMockLogger(),
2026-09-10 12:26:25 -07:00
monitorsRepository: { updateById: jest.fn().mockResolvedValue({}), findDockerTlsKeyById: jest.fn().mockResolvedValue(null) },
2026-06-18 11:06:57 -07:00
maintenanceWindowsRepository: { findByMonitorId: jest.fn().mockResolvedValue([]) },
checkService: { toCheck: jest.fn().mockReturnValue({ id: "check-1" }) },
networkService: { requestStatus: jest.fn().mockResolvedValue({ monitorId: "m1", status: true, code: 200, message: "OK" }) },
2026-08-21 11:41:26 -07:00
proxyResolver: { resolve: jest.fn().mockResolvedValue(undefined) },
2026-06-18 11:06:57 -07:00
buffer: { addToBuffer: jest.fn() },
2026-09-03 12:56:44 -07:00
dockerLogsService: { buildDockerLogs: jest.fn().mockResolvedValue([]) },
2026-06-18 11:06:57 -07:00
...overrides,
};
const producer = new CheckProducer(
defaults.monitorsRepository as any,
defaults.maintenanceWindowsRepository as any,
defaults.checkService as any,
defaults.networkService as any,
2026-08-21 11:41:26 -07:00
defaults.proxyResolver as any,
2026-06-18 11:06:57 -07:00
defaults.buffer as any,
2026-09-03 12:56:44 -07:00
defaults.dockerLogsService as any,
2026-06-18 11:06:57 -07:00
defaults.logger as any
);
return { producer, defaults };
};
describe("CheckProducer", () => {
it("throws when monitor id is missing", async () => {
const { producer } = createProducer();
await expect(producer.produce({} as Monitor)).rejects.toThrow("No monitor id");
});
// ── maintenance gate ──────────────────────────────────────────────────────
it("skips the check and flips status to 'maintenance' when in a maintenance window", async () => {
const { producer, defaults } = createProducer({
maintenanceWindowsRepository: { findByMonitorId: jest.fn().mockResolvedValue([activeWindow()]) },
});
const result = await producer.produce(makeMonitor({ status: "up" }));
expect(result).toBeNull();
2026-06-19 10:02:06 -07:00
expect(defaults.monitorsRepository.updateById).toHaveBeenCalledWith("m1", "team", { status: "maintenance", statusWindow: [] });
2026-06-18 11:06:57 -07:00
expect(defaults.networkService.requestStatus).not.toHaveBeenCalled();
expect(defaults.buffer.addToBuffer).not.toHaveBeenCalled();
});
it("does not re-write status when already in maintenance", async () => {
const { producer, defaults } = createProducer({
maintenanceWindowsRepository: { findByMonitorId: jest.fn().mockResolvedValue([activeWindow()]) },
});
const result = await producer.produce(makeMonitor({ status: "maintenance" }));
expect(result).toBeNull();
expect(defaults.monitorsRepository.updateById).not.toHaveBeenCalled();
});
it("proceeds with the check when the maintenance window is inactive", async () => {
const { producer, defaults } = createProducer({
maintenanceWindowsRepository: { findByMonitorId: jest.fn().mockResolvedValue([{ ...activeWindow(), active: false }]) },
});
await producer.produce(makeMonitor());
expect(defaults.networkService.requestStatus).toHaveBeenCalled();
});
2026-08-21 11:41:26 -07:00
// ── proxy resolution ──────────────────────────────────────────────────────
it("passes the resolved proxy url into requestStatus", async () => {
const { producer, defaults } = createProducer({
proxyResolver: { resolve: jest.fn().mockResolvedValue("http://proxy.example.com:8080") },
});
const monitor = makeMonitor();
await producer.produce(monitor);
expect(defaults.networkService.requestStatus).toHaveBeenCalledWith(monitor, { proxyUrl: "http://proxy.example.com:8080" });
});
it("still produces a check when the resolver returns undefined", async () => {
const { producer, defaults } = createProducer();
const monitor = makeMonitor();
const result = await producer.produce(monitor);
expect(defaults.networkService.requestStatus).toHaveBeenCalledWith(monitor, { proxyUrl: undefined });
expect(result).toEqual({ status: expect.objectContaining({ monitorId: "m1" }), check: { id: "check-1" } });
});
2026-06-18 11:06:57 -07:00
// ── acquire / record ──────────────────────────────────────────────────────
2026-09-10 12:26:25 -07:00
// ── docker tls key resolution ─────────────────────────────────────────────
it("fetches the stored key for a docker monitor with a key set and passes it in the context", async () => {
const { producer, defaults } = createProducer({
monitorsRepository: { updateById: jest.fn(), findDockerTlsKeyById: jest.fn().mockResolvedValue("v1.abc123.iv.tag.data") },
});
const monitor = makeMonitor({ type: "docker", url: "tcp://host", dockerTlsKeySet: true });
await producer.produce(monitor);
expect(defaults.monitorsRepository.findDockerTlsKeyById).toHaveBeenCalledWith("m1");
expect(defaults.networkService.requestStatus).toHaveBeenCalledWith(monitor, { proxyUrl: undefined, dockerTlsKey: "v1.abc123.iv.tag.data" });
});
it("does not fetch a key for a docker monitor without one set", async () => {
const { producer, defaults } = createProducer();
const monitor = makeMonitor({ type: "docker", url: "unix:///var/run/docker.sock", dockerTlsKeySet: false });
await producer.produce(monitor);
expect(defaults.monitorsRepository.findDockerTlsKeyById).not.toHaveBeenCalled();
expect(defaults.networkService.requestStatus).toHaveBeenCalledWith(monitor, { proxyUrl: undefined, dockerTlsKey: undefined });
});
it("does not fetch a key for non-docker monitors even if the flag is set", async () => {
const { producer, defaults } = createProducer();
await producer.produce(makeMonitor({ type: "http", dockerTlsKeySet: true }));
expect(defaults.monitorsRepository.findDockerTlsKeyById).not.toHaveBeenCalled();
});
it("passes undefined when the flag is set but the repository has no key", async () => {
const { producer, defaults } = createProducer();
const monitor = makeMonitor({ type: "docker", url: "tcp://host", dockerTlsKeySet: true });
await producer.produce(monitor);
expect(defaults.monitorsRepository.findDockerTlsKeyById).toHaveBeenCalledWith("m1");
expect(defaults.networkService.requestStatus).toHaveBeenCalledWith(monitor, { proxyUrl: undefined, dockerTlsKey: undefined });
});
2026-06-18 11:06:57 -07:00
it("throws when the network response is null", async () => {
const { producer } = createProducer({
networkService: { requestStatus: jest.fn().mockResolvedValue(null) },
});
await expect(producer.produce(makeMonitor())).rejects.toThrow("No network response");
});
it("returns null, warns, and does not buffer when toCheck yields nothing", async () => {
const { producer, defaults } = createProducer({
checkService: { toCheck: jest.fn().mockReturnValue(null) },
});
const result = await producer.produce(makeMonitor());
expect(result).toBeNull();
expect(defaults.logger.warn).toHaveBeenCalledWith(expect.objectContaining({ message: expect.stringContaining("No check could be built") }));
expect(defaults.buffer.addToBuffer).not.toHaveBeenCalled();
});
it("buffers the built check and returns the status and check on success", async () => {
const status = { monitorId: "m1", status: false, code: 500, message: "Error" };
const check = { id: "check-1" };
const { producer, defaults } = createProducer({
networkService: { requestStatus: jest.fn().mockResolvedValue(status) },
checkService: { toCheck: jest.fn().mockReturnValue(check) },
});
const result = await producer.produce(makeMonitor());
expect(defaults.buffer.addToBuffer).toHaveBeenCalledWith(check);
expect(result).toEqual({ status, check });
});
2026-09-03 12:56:44 -07:00
it("builds and buffers docker logs for a docker status", async () => {
const status = { type: "docker", monitorId: "m1", teamId: "team", status: true, code: 200, message: "OK", payload: {} };
const dockerLogs = [{ id: "docker-log-1" }, { id: "docker-log-2" }];
const { producer, defaults } = createProducer({
networkService: { requestStatus: jest.fn().mockResolvedValue(status) },
buffer: { addToBuffer: jest.fn(), addDockerLogToBuffer: jest.fn() },
dockerLogsService: { buildDockerLogs: jest.fn().mockResolvedValue(dockerLogs) },
});
await producer.produce(makeMonitor({ type: "docker" }));
expect(defaults.dockerLogsService.buildDockerLogs).toHaveBeenCalledWith(status);
expect(defaults.buffer.addDockerLogToBuffer).toHaveBeenNthCalledWith(1, dockerLogs[0]);
expect(defaults.buffer.addDockerLogToBuffer).toHaveBeenNthCalledWith(2, dockerLogs[1]);
});
it("does not build docker logs for a non-docker status", async () => {
const { producer, defaults } = createProducer();
await producer.produce(makeMonitor());
expect(defaults.dockerLogsService.buildDockerLogs).not.toHaveBeenCalled();
});
2026-06-18 11:06:57 -07:00
});