Protect upload cleanup and atomic completion paths, add durable media worker leases and brand asset validation, and introduce verified migration/bootstrap/deployment gates.
74 lines
2.4 KiB
TypeScript
74 lines
2.4 KiB
TypeScript
/** @jest-environment node */
|
||
|
||
import { prisma } from '@/lib/prisma'
|
||
import { inspectTaskMaterialCompletionAfterError } from '@/lib/task-material-completion-safety'
|
||
|
||
jest.mock('@/lib/prisma', () => ({
|
||
prisma: {
|
||
material: { findUnique: jest.fn() },
|
||
},
|
||
}))
|
||
|
||
describe('task material completion acknowledgement safety', () => {
|
||
beforeEach(() => {
|
||
jest.clearAllMocks()
|
||
})
|
||
|
||
test.each([
|
||
['processing', 'processing'],
|
||
['failed', 'other'],
|
||
[null, 'other'],
|
||
] as const)('数据库状态 %s 映射为 %s', async (taskStatus, expectedState) => {
|
||
;(prisma.material.findUnique as jest.Mock).mockResolvedValue({
|
||
taskStatus,
|
||
previewUrl: '',
|
||
zipFilePath: '',
|
||
assets: [],
|
||
})
|
||
|
||
await expect(inspectTaskMaterialCompletionAfterError('material-1')).resolves.toMatchObject({
|
||
state: expectedState,
|
||
})
|
||
})
|
||
|
||
test('只有预览、ZIP 与两类资产证据齐全才映射为 completed', async () => {
|
||
;(prisma.material.findUnique as jest.Mock).mockResolvedValue({
|
||
taskStatus: 'completed',
|
||
previewUrl: 'https://s3.example/preview.webp',
|
||
zipFilePath: 'materials/source.zip',
|
||
assets: [{ assetType: 'preview' }, { assetType: 'zip' }],
|
||
})
|
||
|
||
await expect(inspectTaskMaterialCompletionAfterError('material-1')).resolves.toMatchObject({
|
||
state: 'completed',
|
||
})
|
||
})
|
||
|
||
test.each([
|
||
['', 'materials/source.zip', [{ assetType: 'preview' }, { assetType: 'zip' }]],
|
||
['https://s3.example/preview.webp', '', [{ assetType: 'preview' }, { assetType: 'zip' }]],
|
||
['https://s3.example/preview.webp', 'materials/source.zip', [{ assetType: 'preview' }]],
|
||
])('已完成但证据不全时映射为 completed_incomplete', async (previewUrl, zipFilePath, assets) => {
|
||
;(prisma.material.findUnique as jest.Mock).mockResolvedValue({
|
||
taskStatus: 'completed',
|
||
previewUrl,
|
||
zipFilePath,
|
||
assets,
|
||
})
|
||
|
||
await expect(inspectTaskMaterialCompletionAfterError('material-1')).resolves.toMatchObject({
|
||
state: 'completed_incomplete',
|
||
})
|
||
})
|
||
|
||
test('查询失败时返回 unknown,调用方必须保留文件', async () => {
|
||
const error = new Error('database unavailable')
|
||
;(prisma.material.findUnique as jest.Mock).mockRejectedValue(error)
|
||
|
||
await expect(inspectTaskMaterialCompletionAfterError('material-1')).resolves.toEqual({
|
||
state: 'unknown',
|
||
error,
|
||
})
|
||
})
|
||
})
|