2026-05-25 15:36:51 +08:00

105 lines
3.0 KiB
TypeScript

import { mkdtemp, rm, writeFile } from 'fs/promises'
import { tmpdir } from 'os'
import path from 'path'
import { NextRequest } from 'next/server'
import { GET } from '../route'
jest.mock('@/lib/auth', () => ({
authOptions: {},
}))
jest.mock('next-auth', () => ({
getServerSession: jest.fn(),
}))
jest.mock('@/lib/prisma', () => ({
prisma: {
user: {
findUnique: jest.fn(),
},
material: {
findUnique: jest.fn(),
update: jest.fn(),
},
$executeRaw: jest.fn(),
},
}))
jest.mock('@/lib/s3', () => ({
getS3ObjectStream: jest.fn(),
isS3Url: jest.fn(() => false),
}))
jest.mock('@/lib/material-download-log', () => ({
ensureMaterialDownloadLogsTable: jest.fn(),
}))
const { getServerSession } = require('next-auth')
const { prisma } = require('@/lib/prisma')
const { getS3ObjectStream } = require('@/lib/s3')
const { ensureMaterialDownloadLogsTable } = require('@/lib/material-download-log')
describe('GET /api/materials/download', () => {
let tempDir: string
let filePath: string
beforeEach(async () => {
jest.resetAllMocks()
tempDir = await mkdtemp(path.join(tmpdir(), 'flnxi-download-'))
filePath = path.join(tempDir, 'source.zip')
await writeFile(filePath, '0123456789')
getServerSession.mockResolvedValue({
user: {
id: 'owner-1',
role: 'ADMIN',
email: 'owner@example.com',
},
})
prisma.material.findUnique.mockResolvedValue({
id: 'material-1',
userId: 'owner-1',
productModel: 'MODEL',
zipFilePath: filePath,
zipFileName: 'source.zip',
materialType: '3DMAX',
categoryName: '分类',
sceneName: '场景',
authorName: '作者',
})
})
afterEach(async () => {
await rm(tempDir, { recursive: true, force: true })
})
test('legacy 本地文件下载应流式返回完整文件', async () => {
const response = await GET(new NextRequest('http://localhost/api/materials/download?id=material-1'))
await expect(response.text()).resolves.toBe('0123456789')
expect(response.status).toBe(200)
expect(response.headers.get('content-length')).toBe('10')
expect(response.headers.get('accept-ranges')).toBe('bytes')
expect(response.headers.get('content-disposition')).toContain("filename*=UTF-8''")
expect(getS3ObjectStream).not.toHaveBeenCalled()
expect(ensureMaterialDownloadLogsTable).not.toHaveBeenCalled()
})
test('legacy 本地文件 Range 下载应只返回指定范围', async () => {
const response = await GET(
new NextRequest('http://localhost/api/materials/download?id=material-1', {
headers: {
range: 'bytes=3-6',
},
})
)
await expect(response.text()).resolves.toBe('3456')
expect(response.status).toBe(206)
expect(response.headers.get('content-range')).toBe('bytes 3-6/10')
expect(response.headers.get('content-length')).toBe('4')
expect(response.headers.get('content-disposition')).toContain("filename*=UTF-8''")
})
})