Files
Checkmate/server/tests/services/infrastructure/JobGenerator.test.js
T

149 lines
5.4 KiB
JavaScript

import JobGenerator from "@/services/infrastructure/JobGenerator.js";
// Minimal monitor/check shapes
const monitor = { _id: "m1", type: "http" };
const infraMonitor = { _id: "m2", type: "infrastructure" };
const buildDeps = () => {
const networkService = { requestStatus: jest.fn() };
const checkService = { buildCheck: jest.fn(), cleanupOrphanedChecks: jest.fn() };
const monitorStatsService = { cleanupOrphanedMonitorStats: jest.fn() };
const statusService = {
updateMonitorStatus: jest.fn(),
updateMonitorStats: jest.fn(),
evaluateThresholds: jest.fn(),
};
const notificationService = { handleNotifications: jest.fn().mockResolvedValue(true) };
const maintenanceService = { isInMaintenance: jest.fn().mockResolvedValue(false) };
const incidentService = {
handleStatusChange: jest.fn(),
handleThresholdBreach: jest.fn(),
cleanupOrphanedIncidents: jest.fn(),
};
return {
networkService,
checkService,
monitorStatsService,
statusService,
notificationService,
incidentService,
maintenanceService,
};
};
describe("JobGenerator", () => {
it("skips job when in maintenance window", async () => {
const d = buildDeps();
d.maintenanceService.isInMaintenance.mockResolvedValue(true);
const gen = new JobGenerator(
d.networkService,
d.checkService,
d.monitorStatsService,
d.statusService,
d.notificationService,
d.incidentService,
d.maintenanceService
);
const job = gen.generateJob();
await expect(job(monitor)).resolves.toBeUndefined();
expect(d.networkService.requestStatus).not.toHaveBeenCalled();
});
it("runs full flow for http monitor, triggers notifications only on status change", async () => {
const d = buildDeps();
d.networkService.requestStatus.mockResolvedValue({ status: "up" });
const fakeCheck = { save: jest.fn().mockResolvedValue(true) };
d.checkService.buildCheck.mockResolvedValue(fakeCheck);
d.statusService.updateMonitorStatus.mockResolvedValue([{ _id: "m1", type: "http" }, true]);
d.statusService.updateMonitorStats.mockResolvedValue({});
d.incidentService.handleStatusChange.mockResolvedValue({ id: "incident1" });
const gen = new JobGenerator(
d.networkService,
d.checkService,
d.monitorStatsService,
d.statusService,
d.notificationService,
d.incidentService,
d.maintenanceService
);
const job = gen.generateJob();
await job(monitor);
expect(d.networkService.requestStatus).toHaveBeenCalledWith(monitor);
expect(d.checkService.buildCheck).toHaveBeenCalled();
expect(fakeCheck.save).toHaveBeenCalled();
expect(d.statusService.updateMonitorStatus).toHaveBeenCalled();
expect(d.incidentService.handleStatusChange).toHaveBeenCalled();
expect(d.notificationService.handleNotifications).toHaveBeenCalled();
expect(d.statusService.updateMonitorStats).toHaveBeenCalled();
// Not an infra monitor, so evaluateThresholds not called
expect(d.statusService.evaluateThresholds).not.toHaveBeenCalled();
});
it("evaluates thresholds and may notify for infrastructure monitors", async () => {
const d = buildDeps();
d.networkService.requestStatus.mockResolvedValue({ status: "up" });
const fakeCheck = { save: jest.fn().mockResolvedValue(true) };
d.checkService.buildCheck.mockResolvedValue(fakeCheck);
d.statusService.updateMonitorStatus.mockResolvedValue([{ _id: "m2", type: "infrastructure" }, false]);
d.statusService.updateMonitorStats.mockResolvedValue({});
d.statusService.evaluateThresholds.mockResolvedValue({ hasBreach: true, notes: [], metrics: {} });
d.incidentService.handleThresholdBreach.mockResolvedValue({ id: "incident2" });
const gen = new JobGenerator(
d.networkService,
d.checkService,
d.monitorStatsService,
d.statusService,
d.notificationService,
d.incidentService,
d.maintenanceService
);
const job = gen.generateJob();
await job(infraMonitor);
expect(d.statusService.evaluateThresholds).toHaveBeenCalled();
expect(d.incidentService.handleThresholdBreach).toHaveBeenCalled();
expect(d.notificationService.handleNotifications).toHaveBeenCalled();
});
it("propagates errors thrown during job execution", async () => {
const d = buildDeps();
d.networkService.requestStatus.mockRejectedValue(new Error("net"));
const gen = new JobGenerator(
d.networkService,
d.checkService,
d.monitorStatsService,
d.statusService,
d.notificationService,
d.incidentService,
d.maintenanceService
);
const job = gen.generateJob();
await expect(job(monitor)).rejects.toThrow("net");
});
it("cleanup job runs all cleanup steps and propagates errors", async () => {
const d = buildDeps();
const gen = new JobGenerator(
d.networkService,
d.checkService,
d.monitorStatsService,
d.statusService,
d.notificationService,
d.incidentService,
d.maintenanceService
);
const cleanup = gen.generateCleanupJob();
await cleanup();
expect(d.checkService.cleanupOrphanedChecks).toHaveBeenCalled();
expect(d.monitorStatsService.cleanupOrphanedMonitorStats).toHaveBeenCalled();
expect(d.incidentService.cleanupOrphanedIncidents).toHaveBeenCalled();
// error propagation
d.checkService.cleanupOrphanedChecks.mockRejectedValueOnce(new Error("oops"));
await expect(cleanup()).rejects.toThrow("oops");
});
});