167 lines
5.2 KiB
TypeScript
167 lines
5.2 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
const getProviderConfigMock = vi.hoisted(() => vi.fn(async () => ({
|
|
id: 'openai-compatible:oa-1',
|
|
apiKey: 'sk-test',
|
|
baseUrl: 'https://compat.example.com/v1',
|
|
})))
|
|
const getUserModelsMock = vi.hoisted(() =>
|
|
vi.fn<typeof import('@/lib/api-config').getUserModels>(async () => []),
|
|
)
|
|
|
|
vi.mock('@/lib/api-config', () => ({
|
|
getProviderConfig: getProviderConfigMock,
|
|
getUserModels: getUserModelsMock,
|
|
}))
|
|
|
|
import { pollAsyncTask } from '@/lib/async-poll'
|
|
|
|
function encode(value: string): string {
|
|
return Buffer.from(value, 'utf8').toString('base64url')
|
|
}
|
|
|
|
describe('async poll ocompat', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
globalThis.fetch = vi.fn() as unknown as typeof fetch
|
|
})
|
|
|
|
it('returns completed with output url when async status reaches done', async () => {
|
|
getUserModelsMock.mockResolvedValueOnce([
|
|
{
|
|
modelKey: 'openai-compatible:oa-1::veo3.1',
|
|
modelId: 'veo3.1',
|
|
name: 'Veo 3.1',
|
|
type: 'video',
|
|
provider: 'openai-compatible:oa-1',
|
|
price: 0,
|
|
compatMediaTemplate: {
|
|
version: 1,
|
|
mediaType: 'video',
|
|
mode: 'async',
|
|
create: { method: 'POST', path: '/v2/videos/generations' },
|
|
status: { method: 'GET', path: '/v2/videos/generations/{{task_id}}' },
|
|
response: {
|
|
statusPath: '$.status',
|
|
outputUrlPath: '$.video_url',
|
|
},
|
|
polling: {
|
|
intervalMs: 3000,
|
|
timeoutMs: 180000,
|
|
doneStates: ['succeeded'],
|
|
failStates: ['failed'],
|
|
},
|
|
},
|
|
},
|
|
])
|
|
const fetchMock = vi.fn(async () => new Response(JSON.stringify({
|
|
status: 'succeeded',
|
|
video_url: 'https://cdn.test/video.mp4',
|
|
}), { status: 200 }))
|
|
globalThis.fetch = fetchMock as unknown as typeof fetch
|
|
|
|
const result = await pollAsyncTask(
|
|
`OCOMPAT:VIDEO:${encode('openai-compatible:oa-1')}:${encode('openai-compatible:oa-1::veo3.1')}:task_1`,
|
|
'user-1',
|
|
)
|
|
|
|
expect(result).toEqual({
|
|
status: 'completed',
|
|
resultUrl: 'https://cdn.test/video.mp4',
|
|
videoUrl: 'https://cdn.test/video.mp4',
|
|
})
|
|
})
|
|
|
|
it('uses content endpoint when output url is missing', async () => {
|
|
getUserModelsMock.mockResolvedValueOnce([
|
|
{
|
|
modelKey: 'openai-compatible:oa-1::veo3.1',
|
|
modelId: 'veo3.1',
|
|
name: 'Veo 3.1',
|
|
type: 'video',
|
|
provider: 'openai-compatible:oa-1',
|
|
price: 0,
|
|
compatMediaTemplate: {
|
|
version: 1,
|
|
mediaType: 'video',
|
|
mode: 'async',
|
|
create: { method: 'POST', path: '/v2/videos/generations' },
|
|
status: { method: 'GET', path: '/v2/videos/generations/{{task_id}}' },
|
|
content: { method: 'GET', path: '/v2/videos/generations/{{task_id}}/content' },
|
|
response: {
|
|
statusPath: '$.status',
|
|
},
|
|
polling: {
|
|
intervalMs: 3000,
|
|
timeoutMs: 180000,
|
|
doneStates: ['succeeded'],
|
|
failStates: ['failed'],
|
|
},
|
|
},
|
|
},
|
|
])
|
|
const fetchMock = vi.fn(async () => new Response(JSON.stringify({
|
|
status: 'succeeded',
|
|
}), { status: 200 }))
|
|
globalThis.fetch = fetchMock as unknown as typeof fetch
|
|
|
|
const result = await pollAsyncTask(
|
|
`OCOMPAT:VIDEO:${encode('openai-compatible:oa-1')}:${encode('openai-compatible:oa-1::veo3.1')}:task_2`,
|
|
'user-1',
|
|
)
|
|
|
|
expect(result.status).toBe('completed')
|
|
expect(result.videoUrl).toBe('https://compat.example.com/v1/v2/videos/generations/task_2/content')
|
|
expect(result.downloadHeaders).toEqual({
|
|
Authorization: 'Bearer sk-test',
|
|
})
|
|
})
|
|
|
|
it('accepts compact OCOMPAT token encoded from modelId', async () => {
|
|
const providerUuid = '33331fb0-2806-4da6-85ff-cd2433b587d0'
|
|
getUserModelsMock.mockResolvedValueOnce([
|
|
{
|
|
modelKey: `openai-compatible:${providerUuid}::veo3.1-fast`,
|
|
modelId: 'veo3.1-fast',
|
|
name: 'Veo 3.1 Fast',
|
|
type: 'video',
|
|
provider: `openai-compatible:${providerUuid}`,
|
|
price: 0,
|
|
compatMediaTemplate: {
|
|
version: 1,
|
|
mediaType: 'video',
|
|
mode: 'async',
|
|
create: { method: 'POST', path: '/video/create' },
|
|
status: { method: 'GET', path: '/video/query?id={{task_id}}' },
|
|
response: {
|
|
statusPath: '$.status',
|
|
outputUrlPath: '$.video_url',
|
|
},
|
|
polling: {
|
|
intervalMs: 3000,
|
|
timeoutMs: 180000,
|
|
doneStates: ['completed'],
|
|
failStates: ['failed'],
|
|
},
|
|
},
|
|
},
|
|
])
|
|
const fetchMock = vi.fn(async () => new Response(JSON.stringify({
|
|
status: 'completed',
|
|
video_url: 'https://cdn.test/video-fast.mp4',
|
|
}), { status: 200 }))
|
|
globalThis.fetch = fetchMock as unknown as typeof fetch
|
|
|
|
const result = await pollAsyncTask(
|
|
`OCOMPAT:VIDEO:u_${providerUuid}:${encode('veo3.1-fast')}:task_3`,
|
|
'user-1',
|
|
)
|
|
|
|
expect(result).toEqual({
|
|
status: 'completed',
|
|
resultUrl: 'https://cdn.test/video-fast.mp4',
|
|
videoUrl: 'https://cdn.test/video-fast.mp4',
|
|
})
|
|
})
|
|
})
|