import { beforeEach, describe, expect, it, vi } from "vitest"; import type { ContainerLifecycleService } from "../container-lifecycle/container-lifecycle.service"; import { ContainerReaperService } from "./container-reaper.service"; describe("ContainerReaperService", () => { let service: ContainerReaperService; let containerLifecycle: Pick; beforeEach(() => { containerLifecycle = { reapIdle: vi.fn(), }; service = new ContainerReaperService(containerLifecycle as ContainerLifecycleService); }); it("reapIdleContainers calls containerLifecycle.reapIdle()", async () => { vi.mocked(containerLifecycle.reapIdle).mockResolvedValue({ stopped: [] }); await service.reapIdleContainers(); expect(containerLifecycle.reapIdle).toHaveBeenCalledTimes(1); }); it("reapIdleContainers handles errors gracefully", async () => { const error = new Error("reap failure"); vi.mocked(containerLifecycle.reapIdle).mockRejectedValue(error); const loggerError = vi.spyOn(service["logger"], "error").mockImplementation(() => {}); await expect(service.reapIdleContainers()).resolves.toBeUndefined(); expect(loggerError).toHaveBeenCalledWith( "Failed to reap idle containers", expect.stringContaining("reap failure") ); }); it("reapIdleContainers logs stopped container count", async () => { vi.mocked(containerLifecycle.reapIdle).mockResolvedValue({ stopped: ["user-1", "user-2"] }); const loggerLog = vi.spyOn(service["logger"], "log").mockImplementation(() => {}); await service.reapIdleContainers(); expect(loggerLog).toHaveBeenCalledWith("Stopped 2 idle containers: user-1, user-2"); }); });