import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' import { SHUTDOWN_TIMEOUT_MS } from '../../server/utils/constants.js' import { registerCleanup, graceful, initShutdownHandlers, clearCleanup } from '../../server/utils/shutdown.js' describe('shutdown integration', () => { /** @type {import('vitest').MockInstance} */ let exitSpy /** @type {typeof process.on} */ let originalOn beforeEach(() => { clearCleanup() exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => {}) originalOn = process.on }) afterEach(() => { exitSpy.mockRestore() process.on = originalOn clearCleanup() vi.useRealTimers() }) it('initializes signal handlers', () => { const handlers = {} process.on = vi.fn((signal, handler) => { handlers[signal] = handler }) initShutdownHandlers() expect(process.on).toHaveBeenCalledWith('SIGTERM', expect.any(Function)) expect(process.on).toHaveBeenCalledWith('SIGINT', expect.any(Function)) }) it('signal handler calls graceful', async () => { const handlers = {} process.on = vi.fn((signal, handler) => { handlers[signal] = handler }) initShutdownHandlers() const sigtermHandler = handlers.SIGTERM expect(sigtermHandler).toBeDefined() sigtermHandler() await vi.waitFor(() => { expect(exitSpy).toHaveBeenCalled() }) }) it('signal handler handles graceful error', async () => { const handlers = {} process.on = vi.fn((signal, handler) => { handlers[signal] = handler }) initShutdownHandlers() const sigintHandler = handlers.SIGINT vi.spyOn(console, 'error').mockImplementation(() => {}) registerCleanup(async () => { throw new Error('Force error') }) sigintHandler() await vi.waitFor(() => { expect(exitSpy).toHaveBeenCalled() }) }) it('covers timeout path in graceful', async () => { vi.useFakeTimers() registerCleanup(async () => { await new Promise(resolve => setTimeout(resolve, SHUTDOWN_TIMEOUT_MS + 5_000)) }) graceful() await vi.advanceTimersByTimeAsync(SHUTDOWN_TIMEOUT_MS + 1) expect(exitSpy).toHaveBeenCalledWith(1) }) it('covers graceful catch block', async () => { registerCleanup(async () => { throw new Error('Test error') }) await graceful() expect(exitSpy).toHaveBeenCalled() }) })