refactor(desktop): session-scoped voice runtime, STT/LLM ports, caption ownership and meeting export fixes
This commit is contained in:
parent
0adedf5e7b
commit
83cf9133ac
39 changed files with 4787 additions and 1061 deletions
|
|
@ -0,0 +1,75 @@
|
|||
// tests/main/services/audio-capture-redteam-r1-3.test.ts
|
||||
// SoX 가 장치를 못 열고 끝났을 때 'error' 리스너가 없어 ERR_UNHANDLED_ERROR 가 나고
|
||||
// 뒤이은 'stopped' 가 영영 나가지 않던 버그의 회귀 테스트.
|
||||
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
||||
import { EventEmitter } from 'events'
|
||||
|
||||
vi.mock('../../../src/main/services/LoggerService', () => ({
|
||||
getLogger: () => ({ info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() }),
|
||||
}))
|
||||
|
||||
vi.mock('../../../src/main/services/ConfigService', () => ({
|
||||
configGet: vi.fn(() => 'usb-headset-gone'),
|
||||
}))
|
||||
|
||||
vi.mock('../../../src/main/utils/paths', () => ({
|
||||
getSoxPath: () => 'sox',
|
||||
}))
|
||||
|
||||
class FakeProcess extends EventEmitter {
|
||||
stdout = new EventEmitter()
|
||||
stderr = new EventEmitter()
|
||||
kill = vi.fn()
|
||||
}
|
||||
|
||||
const spawned = vi.hoisted(() => ({ list: [] as unknown[] }))
|
||||
|
||||
vi.mock('child_process', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('child_process')>()
|
||||
return {
|
||||
...actual,
|
||||
spawn: vi.fn(() => {
|
||||
const proc = new FakeProcess()
|
||||
spawned.list.push(proc)
|
||||
return proc
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
type Module = typeof import('../../../src/main/services/AudioCaptureService')
|
||||
let mod: Module
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.resetModules()
|
||||
spawned.list = []
|
||||
mod = await import('../../../src/main/services/AudioCaptureService')
|
||||
mod.resetAudioCaptureServiceForTests()
|
||||
})
|
||||
|
||||
describe('AudioCaptureService — 캡처 프로세스 종료', () => {
|
||||
it("SoX 가 녹음 중 끝나도 예외 없이 'stopped'(device-lost) 를 알린다", async () => {
|
||||
const audio = mod.getAudioCaptureService()
|
||||
const stopped: string[] = []
|
||||
audio.on('stopped', ({ reason }) => stopped.push(reason))
|
||||
|
||||
await audio.start()
|
||||
expect(audio.state).toBe('capturing')
|
||||
|
||||
const proc = spawned.list[0] as FakeProcess
|
||||
expect(() => proc.emit('close', 1)).not.toThrow()
|
||||
|
||||
expect(stopped).toEqual(['device-lost'])
|
||||
expect(audio.state).toBe('error')
|
||||
})
|
||||
|
||||
it('실패 뒤에도 다시 시작할 수 있다', async () => {
|
||||
const audio = mod.getAudioCaptureService()
|
||||
await audio.start()
|
||||
;(spawned.list[0] as FakeProcess).emit('close', 1)
|
||||
|
||||
await audio.start()
|
||||
expect(audio.state).toBe('capturing')
|
||||
expect(spawned.list).toHaveLength(2)
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue