extract flipping monitor status, flip status on delete

This commit is contained in:
Alex Holliday committed 2026-05-21 10:27:46 -07:00
1 parent abf66eed95
commit 0470eab782
2 files changed
+70 -13

No files matched your search

@@ -55,6 +55,24 @@ export class MaintenanceWindowService implements IMaintenanceWindowService {
return MaintenanceWindowService.SERVICE_NAME;
}
private flipMonitorsLeavingMaintenance = async (monitorIds: string[], teamId: string, excludeWindowId: string, now: Date): Promise<void> => {
if (monitorIds.length === 0) return;
const otherWindows = await this.maintenanceWindowsRepository.findByMonitorIds(monitorIds, teamId, excludeWindowId);
const stillCovered = new Set<string>();
for (const otherWindow of otherWindows) {
if (!isWindowActive(otherWindow, now)) continue;
for (const monitorId of otherWindow.monitorIds) {
if (monitorIds.includes(monitorId)) stillCovered.add(monitorId);
}
}
const toInitializing = monitorIds.filter((monitorId) => !stillCovered.has(monitorId));
if (toInitializing.length > 0) {
await this.monitorsRepository.updateByIds(toInitializing, teamId, { status: "initializing" });
}
};
createMaintenanceWindow = async ({
teamId,
monitorIDs,
@@ -134,7 +152,14 @@ export class MaintenanceWindowService implements IMaintenanceWindowService {
};
deleteMaintenanceWindow = async ({ id, teamId }: { id: string; teamId: string }) => {
return await this.maintenanceWindowsRepository.deleteById(id, teamId);
const deleted = await this.maintenanceWindowsRepository.deleteById(id, teamId);
const now = new Date();
if (isWindowActive(deleted, now)) {
await this.flipMonitorsLeavingMaintenance(deleted.monitorIds, teamId, deleted.id, now);
}
return deleted;
};
editMaintenanceWindow = async ({
@@ -180,18 +205,7 @@ export class MaintenanceWindowService implements IMaintenanceWindowService {
}
if (leavingCandidates.length > 0) {
const otherWindows = await this.maintenanceWindowsRepository.findByMonitorIds(leavingCandidates, teamId, existing.id);
const stillCovered = new Set<string>();
for (const otherWindow of otherWindows) {
if (!isWindowActive(otherWindow, now)) continue;
for (const monitorId of otherWindow.monitorIds) {
if (leavingCandidates.includes(monitorId)) stillCovered.add(monitorId);
}
}
const toInitializing = leavingCandidates.filter((monitorId) => !stillCovered.has(monitorId));
if (toInitializing.length > 0) {
await this.monitorsRepository.updateByIds(toInitializing, teamId, { status: "initializing" });
}
await this.flipMonitorsLeavingMaintenance(leavingCandidates, teamId, existing.id, now);
}
return updated;
@@ -233,6 +233,49 @@ describe("MaintenanceWindowService", () => {
expect(result).toBe(deleted);
expect(maintenanceWindowsRepository.deleteById).toHaveBeenCalledWith("mw-1", "team-1");
});
it("does not touch monitor status when deleting an inactive window", async () => {
// default fixture has past dates → inactive
const { service, monitorsRepository, maintenanceWindowsRepository } = createService();
await service.deleteMaintenanceWindow({ id: "mw-1", teamId: "team-1" });
expect(monitorsRepository.updateByIds).not.toHaveBeenCalled();
expect(maintenanceWindowsRepository.findByMonitorIds).not.toHaveBeenCalled();
});
it("flips covered monitors to initializing when deleting an active window", async () => {
const maintenanceWindowsRepository = createMaintenanceWindowsRepo();
(maintenanceWindowsRepository.deleteById as jest.Mock).mockResolvedValue(makeActiveWindow({ monitorIds: ["mon-1", "mon-2"] }));
const { service, monitorsRepository } = createService({ maintenanceWindowsRepository });
await service.deleteMaintenanceWindow({ id: "mw-1", teamId: "team-1" });
expect(monitorsRepository.updateByIds).toHaveBeenCalledTimes(1);
expect(monitorsRepository.updateByIds).toHaveBeenCalledWith(["mon-1", "mon-2"], "team-1", { status: "initializing" });
});
it("excludes the deleted window from the overlap check", async () => {
const maintenanceWindowsRepository = createMaintenanceWindowsRepo();
(maintenanceWindowsRepository.deleteById as jest.Mock).mockResolvedValue(makeActiveWindow({ monitorIds: ["mon-1"] }));
const { service } = createService({ maintenanceWindowsRepository });
await service.deleteMaintenanceWindow({ id: "mw-1", teamId: "team-1" });
expect(maintenanceWindowsRepository.findByMonitorIds).toHaveBeenCalledWith(["mon-1"], "team-1", "mw-1");
});
it("does not flip a monitor still covered by another active window", async () => {
const maintenanceWindowsRepository = createMaintenanceWindowsRepo();
(maintenanceWindowsRepository.deleteById as jest.Mock).mockResolvedValue(makeActiveWindow({ monitorIds: ["mon-1", "mon-2"] }));
(maintenanceWindowsRepository.findByMonitorIds as jest.Mock).mockResolvedValue([makeActiveWindow({ id: "mw-2", monitorIds: ["mon-2"] })]);
const { service, monitorsRepository } = createService({ maintenanceWindowsRepository });
await service.deleteMaintenanceWindow({ id: "mw-1", teamId: "team-1" });
expect(monitorsRepository.updateByIds).toHaveBeenCalledTimes(1);
expect(monitorsRepository.updateByIds).toHaveBeenCalledWith(["mon-1"], "team-1", { status: "initializing" });
});
});
// ── editMaintenanceWindow ────────────────────────────────────────────────