Files
Rune-Spec/tests/helpers/cleanup.test.ts

120 lines
3.1 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.
import { describe, it, expect, mock, beforeEach, afterEach } from "bun:test";
import { mkdir, access, rm } from "node:fs/promises";
import { join } from "node:path";
const TMP_DIR = join(import.meta.dir, "__tmp_cleanup_test__");
async function dirExists(path: string): Promise<boolean> {
try {
await access(path);
return true;
} catch {
return false;
}
}
describe("retryRm", () => {
describe("正常删除", () => {
afterEach(async () => {
if (await dirExists(TMP_DIR)) {
await rm(TMP_DIR, { recursive: true, force: true });
}
});
it("删除存在的目录", async () => {
const { retryRm } = await import("./cleanup.ts");
await mkdir(TMP_DIR, { recursive: true });
await retryRm(TMP_DIR);
expect(await dirExists(TMP_DIR)).toBe(false);
});
it("删除不存在的路径不报错force:true", async () => {
const { retryRm } = await import("./cleanup.ts");
const nonExist = join(import.meta.dir, "__non_exist__");
await expect(retryRm(nonExist)).resolves.toBeUndefined();
});
});
describe("EBUSY 重试后成功", () => {
let callCount: number;
beforeEach(() => {
callCount = 0;
mock.module("node:fs/promises", () => ({
rm: mock(async () => {
callCount++;
if (callCount === 1) {
const err: any = new Error("EBUSY");
err.code = "EBUSY";
throw err;
}
}),
}));
});
afterEach(() => {
mock.restore();
});
it("EBUSY 后重试成功", async () => {
const { retryRm } = await import("./cleanup.ts");
await retryRm("/some/path", { maxRetries: 3, baseDelay: 10 });
expect(callCount).toBe(2);
});
});
describe("重试耗尽后抛出错误", () => {
let callCount: number;
beforeEach(() => {
callCount = 0;
mock.module("node:fs/promises", () => ({
rm: mock(async () => {
callCount++;
const err: any = new Error("EBUSY");
err.code = "EBUSY";
throw err;
}),
}));
});
afterEach(() => {
mock.restore();
});
it("maxRetries 耗尽后抛出最后一个错误", async () => {
const { retryRm } = await import("./cleanup.ts");
await expect(retryRm("/some/path", { maxRetries: 2, baseDelay: 10 })).rejects.toThrow(
"EBUSY",
);
expect(callCount).toBe(3);
});
});
describe("非 EBUSY/EPERM 错误不重试", () => {
let callCount: number;
beforeEach(() => {
callCount = 0;
mock.module("node:fs/promises", () => ({
rm: mock(async () => {
callCount++;
const err: any = new Error("ENOENT: no such file or directory");
err.code = "ENOENT";
throw err;
}),
}));
});
afterEach(() => {
mock.restore();
});
it("ENOENT 错误直接抛出不重试", async () => {
const { retryRm } = await import("./cleanup.ts");
await expect(retryRm("/some/path")).rejects.toThrow("ENOENT");
expect(callCount).toBe(1);
});
});
});