116 lines
3.7 KiB
TypeScript

import { NextRequest } from 'next/server'
import { Readable } from 'stream'
import { GET } from '../route'
jest.mock('@/lib/auth', () => ({
authOptions: {},
}))
jest.mock('next-auth', () => ({
getServerSession: jest.fn(),
}))
jest.mock('@/lib/prisma', () => ({
prisma: {
material: {
findFirst: jest.fn(),
},
},
}))
jest.mock('@/lib/s3', () => ({
getS3ObjectStream: jest.fn(),
isS3Url: jest.fn((value?: string | null) => /^https?:\/\//.test(value || '')),
}))
jest.mock('@/lib/material-share-token', () => ({
findValidMaterialShareToken: jest.fn(),
}))
jest.mock('@/lib/public-share-settings', () => ({
isPublicShareEnabled: jest.fn(),
}))
const { getServerSession } = require('next-auth')
const { prisma } = require('@/lib/prisma')
const { getS3ObjectStream, isS3Url } = require('@/lib/s3')
const { findValidMaterialShareToken } = require('@/lib/material-share-token')
const { isPublicShareEnabled } = require('@/lib/public-share-settings')
describe('GET /api/materials/stream', () => {
beforeEach(() => {
jest.resetAllMocks()
isS3Url.mockImplementation((value?: string | null) => /^https?:\/\//.test(value || ''))
isPublicShareEnabled.mockResolvedValue(true)
})
it('未登录且没有有效分享票据时拒绝播放', async () => {
prisma.material.findFirst.mockResolvedValue({
id: 'material-1',
zipFilePath: 'http://minio:9000/bucket/video.mp4',
zipFileName: 'video.mp4',
materialType: '视频',
materialKind: 'VIDEO',
})
getServerSession.mockResolvedValue(null)
findValidMaterialShareToken.mockResolvedValue(null)
const response = await GET(new NextRequest('http://localhost/api/materials/stream?id=material-1'))
const data = await response.json()
expect(response.status).toBe(401)
expect(data.error).toBe('请先登录或使用有效分享链接')
expect(getS3ObjectStream).not.toHaveBeenCalled()
})
it('未登录但分享票据有效时允许播放', async () => {
prisma.material.findFirst.mockResolvedValue({
id: 'material-1',
zipFilePath: 'http://minio:9000/bucket/video.mp4',
zipFileName: 'video.mp4',
materialType: '视频',
materialKind: 'VIDEO',
})
getServerSession.mockResolvedValue(null)
findValidMaterialShareToken.mockResolvedValue({ id: 'token-row', materialId: 'material-1' })
getS3ObjectStream.mockResolvedValue({
body: Readable.from([Buffer.from('video-body')]),
contentLength: 10,
contentType: 'video/mp4',
acceptRanges: 'bytes',
})
const response = await GET(
new NextRequest('http://localhost/api/materials/stream?id=material-1&shareToken=share-token')
)
const body = await response.text()
expect(response.status).toBe(200)
expect(body).toBe('video-body')
expect(findValidMaterialShareToken).toHaveBeenCalledWith('share-token', 'material-1')
expect(response.headers.get('access-control-allow-origin')).toBeNull()
})
it('公开分享开关关闭时拒绝通过分享票据播放', async () => {
prisma.material.findFirst.mockResolvedValue({
id: 'material-1',
zipFilePath: 'http://minio:9000/bucket/video.mp4',
zipFileName: 'video.mp4',
materialType: '视频',
materialKind: 'VIDEO',
})
getServerSession.mockResolvedValue(null)
isPublicShareEnabled.mockResolvedValue(false)
const response = await GET(
new NextRequest('http://localhost/api/materials/stream?id=material-1&shareToken=share-token')
)
const data = await response.json()
expect(response.status).toBe(403)
expect(data.error).toBe('公开分享功能已关闭')
expect(findValidMaterialShareToken).not.toHaveBeenCalled()
expect(getS3ObjectStream).not.toHaveBeenCalled()
})
})