Files
curriculum-project-hub/hub/test/unit/filelib-file-limits.test.ts
ce5fbfb9a6 fix(filelib): 上传上限抬到 50MiB,并把它与 body limit 的串联写清
7.8MB 文件上传报 413:那是 Fastify 在 body 解析阶段拒的,不是
HUB_FILELIB_MAX_FILE_BYTES。上传把内容放在 JSON body 里、二进制过 base64
体积涨 4/3,所以有效上限是 min(该值, HUB_HTTP_BODY_LIMIT_BYTES × 3/4)。
原先 body limit 是 1MiB,10MiB 的文件上限根本不可达。

.env.example:body limit 1MiB → 70MiB,新增 HUB_FILELIB_MAX_FILE_BYTES=50MiB。
注意 body limit 同时是 ADR-0022 requestBodySize 维度的平台 ceiling,抬高它
对所有端点生效。

resolveMaxFileBytes 拆成 parseMaxFileBytes(纯解析)+ resolveMaxFileBytes(读
env):原先带默认参数,显式传 undefined 会回落到读 env,"没传值"与"读环境变量"
分不开,vitest 加载 .env 后测试会读到真实配置。
2026-07-27 16:14:50 +08:00

74 lines
2.9 KiB
TypeScript

/**
* 单文件上限的环境变量解析 + commit message 默认文案。
*
* 上限:`HUB_FILELIB_MAX_FILE_BYTES` 覆盖,缺省 10MiB;非法值按缺省 ——
* 配置写错不该让上传静默变成 0 上限(那会把每次上传都拒掉)。
* 文案:`【用户名】修改了【路径】`,用户名取 displayName、缺失回退 userId。
*/
import { describe, expect, it } from "vitest";
import {
FILE_CONTENT_MAX_BYTES_DEFAULT,
defaultCommitMessage,
parseMaxFileBytes,
} from "../../src/database/filelib/fileService.js";
describe("parseMaxFileBytes", () => {
it("缺省 10MiB", () => {
expect(FILE_CONTENT_MAX_BYTES_DEFAULT).toBe(10 * 1024 * 1024);
expect(parseMaxFileBytes(undefined)).toBe(FILE_CONTENT_MAX_BYTES_DEFAULT);
expect(parseMaxFileBytes("")).toBe(FILE_CONTENT_MAX_BYTES_DEFAULT);
expect(parseMaxFileBytes(" ")).toBe(FILE_CONTENT_MAX_BYTES_DEFAULT);
});
it("合法正整数生效(可上调也可下调)", () => {
expect(parseMaxFileBytes("1048576")).toBe(1024 * 1024);
expect(parseMaxFileBytes(" 52428800 ")).toBe(50 * 1024 * 1024);
expect(parseMaxFileBytes("1")).toBe(1);
});
it("非法值一律回退缺省,不产生 0 或负数上限", () => {
for (const bad of ["0", "-1", "abc", "1.5", "NaN", "Infinity", "1e999", "10MB"]) {
expect(parseMaxFileBytes(bad)).toBe(FILE_CONTENT_MAX_BYTES_DEFAULT);
}
});
});
describe("defaultCommitMessage", () => {
it("【用户名】修改了【路径】,用户名取 displayName", () => {
expect(defaultCommitMessage({ userId: "u1", isWebsiteAdmin: false, displayName: "张老师" }, "讲义/第一课.md"))
.toBe("【张老师】修改了【讲义/第一课.md】");
});
it("displayName 缺失/空白时回退 userId", () => {
expect(defaultCommitMessage({ userId: "u_alice", isWebsiteAdmin: false }, "a.md"))
.toBe("【u_alice】修改了【a.md】");
expect(defaultCommitMessage({ userId: "u_alice", isWebsiteAdmin: false, displayName: " " }, "a.md"))
.toBe("【u_alice】修改了【a.md】");
});
});
/**
* message 优先级的纯函数复刻(commitFile 里的那三行):
* 非空则用调用方的,否则回退默认文案。空串必须算“没传” ——
* `git commit -m ""` 会以 empty commit message 失败。
*/
function resolveMessage(input: string | undefined, fallback: string): string {
const trimmed = input?.trim();
return trimmed === undefined || trimmed === "" ? fallback : trimmed;
}
describe("commit message 优先级", () => {
const fallback = "【张老师】修改了【a.md】";
it("手填了就用手填的", () => {
expect(resolveMessage("补上第三课的课件", fallback)).toBe("补上第三课的课件");
expect(resolveMessage(" 前后有空格 ", fallback)).toBe("前后有空格");
});
it("未传/空/约空白一律回退默认文案", () => {
for (const raw of [undefined, "", " ", "\n\t"]) {
expect(resolveMessage(raw, fallback)).toBe(fallback);
}
});
});