d3ro-voice/apps/desktop/tests/main/shutdown-registry.test.ts

72 lines
2.8 KiB
TypeScript

// tests/main/shutdown-registry.test.ts
// 종료 등록부 — 역순 정리, 멱등, 멈춘 항목이 종료를 막지 않음.
import { describe, it, expect, vi } from 'vitest'
import { ShutdownRegistry } from '../../src/main/shutdown-registry'
describe('ShutdownRegistry', () => {
it('등록의 역순으로 정리한다', async () => {
const order: string[] = []
const registry = new ShutdownRegistry()
registry.register({ name: 'a', dispose: () => { order.push('a') } })
registry.register({ name: 'b', dispose: async () => { order.push('b') } })
registry.register({ name: 'c', dispose: () => { order.push('c') } })
const report = await registry.disposeAll(1000)
expect(order).toEqual(['c', 'b', 'a'])
expect(report.completed).toEqual(['c', 'b', 'a'])
})
it('여러 번 불러도 한 번만 정리한다', async () => {
const dispose = vi.fn()
const registry = new ShutdownRegistry()
registry.register({ name: 'x', dispose })
await Promise.all([registry.disposeAll(1000), registry.disposeAll(1000)])
await registry.disposeAll(1000)
expect(dispose).toHaveBeenCalledTimes(1)
})
it('실패한 항목은 기록하고 나머지를 계속 정리한다', async () => {
const onError = vi.fn()
const later = vi.fn()
const registry = new ShutdownRegistry({ onError })
registry.register({ name: 'later', dispose: later })
registry.register({ name: 'throws', dispose: () => { throw new Error('sync boom') } })
registry.register({ name: 'rejects', dispose: async () => { throw new Error('async boom') } })
const report = await registry.disposeAll(1000)
expect(report.failed).toEqual(['rejects', 'throws'])
expect(report.completed).toEqual(['later'])
expect(later).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledTimes(2)
})
it('멈춘 항목이 있어도 상한 시간 안에 끝나고, 남은 항목의 dispose 는 걸어 둔다', async () => {
vi.useFakeTimers()
try {
const last = vi.fn()
const registry = new ShutdownRegistry()
registry.register({ name: 'last', dispose: last })
registry.register({ name: 'hangs', dispose: () => new Promise<void>(() => undefined) })
const running = registry.disposeAll(500)
await vi.advanceTimersByTimeAsync(501)
const report = await running
expect(report.timedOut).toEqual(['hangs', 'last'])
// 기다리진 않지만 동기 구간(프로세스 kill 등)은 실행된다
expect(last).toHaveBeenCalledTimes(1)
} finally {
vi.useRealTimers()
}
})
it('등록 취소한 항목은 정리하지 않는다', async () => {
const dispose = vi.fn()
const registry = new ShutdownRegistry()
const unregister = registry.register({ name: 'x', dispose })
unregister()
await registry.disposeAll(1000)
expect(dispose).not.toHaveBeenCalled()
})
})