116 lines
3.7 KiB
TypeScript
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()
|
|
})
|
|
})
|