Files
openclaw/src/agents/auth-profiles/oauth-lock-timeout-classification.test.ts
2026-04-24 11:43:22 +01:00

56 lines
2.0 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { FILE_LOCK_TIMEOUT_ERROR_CODE, type FileLockTimeoutError } from "../../infra/file-lock.js";
import {
buildRefreshContentionError,
isGlobalRefreshLockTimeoutError,
} from "./oauth-refresh-lock-errors.js";
import { resolveAuthStorePath, resolveOAuthRefreshLockPath } from "./paths.js";
function createLockTimeoutError(lockPath: string): FileLockTimeoutError {
return Object.assign(new Error(`file lock timeout for ${lockPath.slice(0, -5)}`), {
code: FILE_LOCK_TIMEOUT_ERROR_CODE as typeof FILE_LOCK_TIMEOUT_ERROR_CODE,
lockPath,
});
}
describe("OAuth refresh lock timeout classification", () => {
it("matches only the global refresh lock path", () => {
const profileId = "openai-codex:default";
const provider = "openai-codex";
const refreshLockPath = resolveOAuthRefreshLockPath(provider, profileId);
const authStoreLockPath = resolveAuthStorePath("/tmp/openclaw-oauth-lock-timeout/agent");
expect(
isGlobalRefreshLockTimeoutError(
createLockTimeoutError(`${refreshLockPath}.lock`),
refreshLockPath,
),
).toBe(true);
expect(
isGlobalRefreshLockTimeoutError(
createLockTimeoutError(`${authStoreLockPath}.lock`),
refreshLockPath,
),
).toBe(false);
});
it("builds refresh_contention errors that preserve the file-lock cause", () => {
const profileId = "openai-codex:default";
const provider = "openai-codex";
const refreshLockPath = resolveOAuthRefreshLockPath(provider, profileId);
const cause = createLockTimeoutError(`${refreshLockPath}.lock`);
const error = buildRefreshContentionError({ provider, profileId, cause });
expect(error).toMatchObject({
code: "refresh_contention",
cause: {
code: FILE_LOCK_TIMEOUT_ERROR_CODE,
lockPath: `${refreshLockPath}.lock`,
},
});
expect(error.message).toContain("another process is already refreshing");
expect(error.message).toContain("Please wait for the in-flight refresh to finish and retry.");
});
});