86 lines
2.8 KiB
TypeScript
86 lines
2.8 KiB
TypeScript
/** @jest-environment node */
|
|
|
|
import { POST } from '@/app/api/materials/upload/refresh/route'
|
|
import { getAuthenticatedUploadUserId } from '@/lib/upload-auth'
|
|
import {
|
|
refreshOwnedUploadSession,
|
|
UploadSessionStoreUnavailableError,
|
|
} from '@/lib/upload-sessions'
|
|
|
|
jest.mock('@/lib/upload-auth', () => ({
|
|
getAuthenticatedUploadUserId: jest.fn(),
|
|
}))
|
|
|
|
jest.mock('@/lib/upload-sessions', () => {
|
|
class MockUploadSessionStoreUnavailableError extends Error {
|
|
constructor(message = '上传会话服务暂时不可用') {
|
|
super(message)
|
|
this.name = 'UploadSessionStoreUnavailableError'
|
|
}
|
|
}
|
|
|
|
return {
|
|
isSafeUploadId: (uploadId: string) => /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/.test(uploadId),
|
|
refreshOwnedUploadSession: jest.fn(),
|
|
UploadSessionStoreUnavailableError: MockUploadSessionStoreUnavailableError,
|
|
}
|
|
})
|
|
|
|
function createRequest(uploadId: unknown) {
|
|
return {
|
|
json: jest.fn().mockResolvedValue({ uploadId }),
|
|
} as any
|
|
}
|
|
|
|
describe('/api/materials/upload/refresh', () => {
|
|
beforeEach(() => {
|
|
jest.clearAllMocks()
|
|
;(getAuthenticatedUploadUserId as jest.Mock).mockResolvedValue('user-1')
|
|
})
|
|
|
|
test('Redis 暂时不可用时返回 503 与可重试提示', async () => {
|
|
;(refreshOwnedUploadSession as jest.Mock).mockRejectedValue(
|
|
new UploadSessionStoreUnavailableError(),
|
|
)
|
|
|
|
const response = await POST(createRequest('upload-active'))
|
|
|
|
expect(response.status).toBe(503)
|
|
expect(response.headers.get('retry-after')).toBe('3')
|
|
await expect(response.json()).resolves.toEqual({
|
|
error: '上传会话服务暂时不可用,已保留上传进度,请稍后重试',
|
|
code: 'UPLOAD_SESSION_STORE_UNAVAILABLE',
|
|
})
|
|
})
|
|
|
|
test.each(['missing', 'forbidden'])('%s 只返回确认不存在的 404 语义', async (result) => {
|
|
;(refreshOwnedUploadSession as jest.Mock).mockResolvedValue(result)
|
|
|
|
const response = await POST(createRequest('upload-missing'))
|
|
|
|
expect(response.status).toBe(404)
|
|
await expect(response.json()).resolves.toEqual({ error: '会话不存在或已过期' })
|
|
})
|
|
|
|
test('合法且属于当前用户的会话刷新成功', async () => {
|
|
;(refreshOwnedUploadSession as jest.Mock).mockResolvedValue('refreshed')
|
|
|
|
const response = await POST(createRequest('upload-owned'))
|
|
|
|
expect(response.status).toBe(200)
|
|
await expect(response.json()).resolves.toEqual({
|
|
success: true,
|
|
uploadId: 'upload-owned',
|
|
ttl: 4 * 60 * 60,
|
|
})
|
|
expect(refreshOwnedUploadSession).toHaveBeenCalledWith('upload-owned', 'user-1')
|
|
})
|
|
|
|
test('非法 uploadId 在访问会话存储前被拒绝', async () => {
|
|
const response = await POST(createRequest('../outside'))
|
|
|
|
expect(response.status).toBe(400)
|
|
expect(refreshOwnedUploadSession).not.toHaveBeenCalled()
|
|
})
|
|
})
|