105 lines
3.0 KiB
TypeScript
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''")
|
|
})
|
|
})
|