gongxiangp2/lib/__tests__/bounded-file-reader.test.ts
chenpei 7326e273e1 fix: harden media upload and release safety
Protect upload cleanup and atomic completion paths, add durable media worker leases and brand asset validation, and introduce verified migration/bootstrap/deployment gates.
2026-08-12 18:04:08 +08:00

98 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/** @jest-environment node */
import { mkdir, mkdtemp, rm, symlink, writeFile } from 'fs/promises'
import os from 'os'
import path from 'path'
import {
readBoundedRegularFile,
readBoundedResponseBuffer,
} from '@/lib/bounded-file-reader'
describe('bounded-file-reader', () => {
let root: string
beforeEach(async () => {
root = await mkdtemp(path.join(os.tmpdir(), 'bounded-file-reader-'))
})
afterEach(async () => {
await rm(root, { recursive: true, force: true })
})
test('在分配 Buffer 前拒绝超限、申报不一致和符号链接文件', async () => {
const filePath = path.join(root, 'source.bin')
await writeFile(filePath, Buffer.from('12345'))
await expect(readBoundedRegularFile(filePath, {
maxBytes: 4,
label: '测试文件',
})).rejects.toThrow('超过 1MB 限制')
await expect(readBoundedRegularFile(filePath, {
maxBytes: 10,
expectedBytes: 4,
label: '测试文件',
})).rejects.toThrow('实际大小与上传记录不一致')
const symlinkTarget = path.join(root, 'source-link-target')
const symlinkPath = path.join(root, 'source-link')
await mkdir(symlinkTarget)
await symlink(symlinkTarget, symlinkPath, process.platform === 'win32' ? 'junction' : 'dir')
await expect(readBoundedRegularFile(symlinkPath, {
maxBytes: 10,
expectedBytes: 5,
label: '测试文件',
})).rejects.toThrow('不是可读取的普通文件')
})
test('普通文件仅在实际大小与申报一致时返回完整内容', async () => {
const filePath = path.join(root, 'source.bin')
await writeFile(filePath, Buffer.from('bounded'))
await expect(readBoundedRegularFile(filePath, {
maxBytes: 64,
expectedBytes: 7,
label: '测试文件',
})).resolves.toEqual(Buffer.from('bounded'))
})
test('远程响应无 Content-Length 时仍按可信大小硬停,且不使用 arrayBuffer', async () => {
const stream = new ReadableStream<Uint8Array>({
start(controller) {
controller.enqueue(new Uint8Array([1, 2]))
controller.enqueue(new Uint8Array([3, 4]))
controller.close()
},
})
const response = new Response(stream)
await expect(readBoundedResponseBuffer(response, {
maxBytes: 4,
expectedBytes: 3,
label: '远程文件',
})).rejects.toThrow('响应超过申报大小')
})
test('远程响应先校验 Content-Length,并按申报大小返回单个 Buffer', async () => {
const response = new Response(Buffer.from('remote'), {
headers: { 'Content-Length': '6' },
})
await expect(readBoundedResponseBuffer(response, {
maxBytes: 10,
expectedBytes: 6,
label: '远程文件',
})).resolves.toEqual(Buffer.from('remote'))
const mismatched = new Response(Buffer.from('remote'), {
headers: { 'Content-Length': '6' },
})
await expect(readBoundedResponseBuffer(mismatched, {
maxBytes: 10,
expectedBytes: 5,
label: '远程文件',
})).rejects.toThrow('响应大小与上传记录不一致')
})
})