Files
waooplus/tests/unit/providers/bailian-voice-cleanup.test.ts
2026-03-08 17:10:06 +08:00

119 lines
3.7 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest'
const prismaMock = vi.hoisted(() => ({
novelPromotionProject: {
findUnique: vi.fn(),
},
novelPromotionCharacter: {
findMany: vi.fn(),
},
globalCharacter: {
findMany: vi.fn(),
},
globalVoice: {
findMany: vi.fn(),
},
novelPromotionEpisode: {
findMany: vi.fn(),
},
}))
const getProviderConfigMock = vi.hoisted(() => vi.fn())
const deleteBailianVoiceMock = vi.hoisted(() => vi.fn())
vi.mock('@/lib/prisma', () => ({
prisma: prismaMock,
}))
vi.mock('@/lib/api-config', () => ({
getProviderConfig: getProviderConfigMock,
}))
vi.mock('@/lib/providers/bailian/voice-manage', () => ({
deleteBailianVoice: deleteBailianVoiceMock,
}))
import {
collectBailianManagedVoiceIds,
collectProjectBailianManagedVoiceIds,
cleanupUnreferencedBailianVoices,
isBailianManagedVoiceBinding,
} from '@/lib/providers/bailian/voice-cleanup'
describe('bailian voice cleanup', () => {
beforeEach(() => {
vi.clearAllMocks()
prismaMock.novelPromotionCharacter.findMany.mockResolvedValue([])
prismaMock.globalCharacter.findMany.mockResolvedValue([])
prismaMock.globalVoice.findMany.mockResolvedValue([])
prismaMock.novelPromotionEpisode.findMany.mockResolvedValue([])
getProviderConfigMock.mockResolvedValue({
apiKey: 'bl-key',
})
deleteBailianVoiceMock.mockResolvedValue({ requestId: 'req-1' })
})
it('identifies managed voice bindings by voiceType or id prefix', () => {
expect(isBailianManagedVoiceBinding({ voiceType: 'qwen-designed', voiceId: 'voice-a' })).toBe(true)
expect(isBailianManagedVoiceBinding({ voiceType: 'uploaded', voiceId: 'qwen-tts-vd-voice-b' })).toBe(true)
expect(isBailianManagedVoiceBinding({ voiceType: 'uploaded', voiceId: 'custom-voice-b' })).toBe(false)
})
it('collects and deduplicates managed voice ids', () => {
const voiceIds = collectBailianManagedVoiceIds([
{ voiceType: 'qwen-designed', voiceId: 'qwen-tts-vd-1' },
{ voiceType: 'qwen-designed', voiceId: 'qwen-tts-vd-1' },
{ voiceType: 'uploaded', voiceId: 'custom-1' },
{ voiceType: null, voiceId: 'qwen-tts-vd-2' },
])
expect(voiceIds).toEqual(['qwen-tts-vd-1', 'qwen-tts-vd-2'])
})
it('deletes only unreferenced managed voices', async () => {
prismaMock.globalVoice.findMany.mockResolvedValue([
{ voiceId: 'qwen-tts-vd-1' },
])
const result = await cleanupUnreferencedBailianVoices({
voiceIds: ['qwen-tts-vd-1', 'qwen-tts-vd-2'],
scope: {
userId: 'user-1',
},
})
expect(getProviderConfigMock).toHaveBeenCalledWith('user-1', 'bailian')
expect(deleteBailianVoiceMock).toHaveBeenCalledTimes(1)
expect(deleteBailianVoiceMock).toHaveBeenCalledWith({
apiKey: 'bl-key',
voiceId: 'qwen-tts-vd-2',
})
expect(result).toEqual({
requestedVoiceIds: ['qwen-tts-vd-1', 'qwen-tts-vd-2'],
skippedReferencedVoiceIds: ['qwen-tts-vd-1'],
deletedVoiceIds: ['qwen-tts-vd-2'],
})
})
it('collects managed voice ids from project characters and speaker voices', async () => {
prismaMock.novelPromotionProject.findUnique.mockResolvedValue({
characters: [
{ voiceId: 'qwen-tts-vd-character', voiceType: 'qwen-designed' },
{ voiceId: 'plain-custom', voiceType: 'uploaded' },
],
episodes: [
{
speakerVoices: JSON.stringify({
Narrator: { voiceType: 'qwen-designed', voiceId: 'qwen-tts-vd-inline' },
Guest: { voiceType: 'uploaded', voiceId: 'uploaded-id' },
}),
},
],
})
const voiceIds = await collectProjectBailianManagedVoiceIds('project-1')
expect(voiceIds).toEqual(['qwen-tts-vd-character', 'qwen-tts-vd-inline'])
})
})