|
|
import { afterEach, describe, expect, it } from "vitest";
|
|
|
import fs from "node:fs";
|
|
|
import path from "node:path";
|
|
|
import {
|
|
|
isFlockNonRetryableFailure,
|
|
|
releaseFlockExclusiveLock,
|
|
|
withFlockExclusiveLock,
|
|
|
} from "@/lib/flock/exclusive-lock";
|
|
|
|
|
|
const LOCK_PATH = path.join(process.cwd(), ".rpa", "flock-rpa.lock");
|
|
|
|
|
|
afterEach(() => {
|
|
|
releaseFlockExclusiveLock("test");
|
|
|
try {
|
|
|
fs.unlinkSync(LOCK_PATH);
|
|
|
} catch {
|
|
|
/* ignore */
|
|
|
}
|
|
|
});
|
|
|
|
|
|
describe("isFlockNonRetryableFailure", () => {
|
|
|
it("识别上限与拒号", () => {
|
|
|
expect(
|
|
|
isFlockNonRetryableFailure(
|
|
|
"FLOCK_QUOTE_LIMIT:Thank you for your interest",
|
|
|
),
|
|
|
).toBe(true);
|
|
|
expect(
|
|
|
isFlockNonRetryableFailure("FLOCK_ACCOUNT_REJECTED:issue creating"),
|
|
|
).toBe(true);
|
|
|
expect(isFlockNonRetryableFailure("互斥锁占用")).toBe(true);
|
|
|
expect(isFlockNonRetryableFailure("网络超时")).toBe(false);
|
|
|
});
|
|
|
});
|
|
|
|
|
|
describe("withFlockExclusiveLock", () => {
|
|
|
it("串行持有锁", async () => {
|
|
|
const order: string[] = [];
|
|
|
await withFlockExclusiveLock("test", async () => {
|
|
|
order.push("a");
|
|
|
expect(fs.existsSync(LOCK_PATH)).toBe(true);
|
|
|
});
|
|
|
expect(fs.existsSync(LOCK_PATH)).toBe(false);
|
|
|
expect(order).toEqual(["a"]);
|
|
|
});
|
|
|
});
|