mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 08:20:43 +00:00
test: narrow auth profile runtime mocks
This commit is contained in:
@@ -25,6 +25,12 @@ async function loadOAuthModuleForTest() {
|
||||
({ resolveApiKeyForProfile, resetOAuthRefreshQueuesForTest } = await import("./oauth.js"));
|
||||
}
|
||||
|
||||
function resolveApiKeyForProfileInTest(
|
||||
params: Omit<Parameters<typeof resolveApiKeyForProfile>[0], "cfg">,
|
||||
) {
|
||||
return resolveApiKeyForProfile({ cfg: {}, ...params });
|
||||
}
|
||||
|
||||
const {
|
||||
refreshProviderOAuthCredentialWithPluginMock,
|
||||
formatProviderAuthProfileApiKeyWithPluginMock,
|
||||
@@ -42,12 +48,32 @@ vi.mock("../cli-credentials.js", () => ({
|
||||
writeCodexCliCredentials: () => true,
|
||||
}));
|
||||
|
||||
vi.mock("@mariozechner/pi-ai/oauth", () => ({
|
||||
getOAuthApiKey: vi.fn(async () => null),
|
||||
getOAuthProviders: () => [{ id: "openai-codex" }, { id: "anthropic" }],
|
||||
}));
|
||||
|
||||
vi.mock("../../plugins/provider-runtime.runtime.js", () => ({
|
||||
formatProviderAuthProfileApiKeyWithPlugin: (params: { context?: { access?: string } }) =>
|
||||
formatProviderAuthProfileApiKeyWithPluginMock() ?? params?.context?.access,
|
||||
refreshProviderOAuthCredentialWithPlugin: refreshProviderOAuthCredentialWithPluginMock,
|
||||
}));
|
||||
|
||||
vi.mock("../../infra/file-lock.js", () => ({
|
||||
resetFileLockStateForTest: () => undefined,
|
||||
withFileLock: async <T>(_filePath: string, _options: unknown, run: () => Promise<T>) => run(),
|
||||
}));
|
||||
|
||||
vi.mock("../../plugin-sdk/file-lock.js", () => ({
|
||||
resetFileLockStateForTest: () => undefined,
|
||||
withFileLock: async <T>(_filePath: string, _options: unknown, run: () => Promise<T>) => run(),
|
||||
}));
|
||||
|
||||
vi.mock("./external-auth.js", () => ({
|
||||
overlayExternalAuthProfiles: <T>(store: T) => store,
|
||||
shouldPersistExternalAuthProfile: () => true,
|
||||
}));
|
||||
|
||||
vi.mock("./doctor.js", () => ({
|
||||
formatAuthDoctorHint: async () => undefined,
|
||||
}));
|
||||
@@ -74,7 +100,11 @@ function storeWith(profileId: string, cred: OAuthCredential): AuthProfileStore {
|
||||
}
|
||||
|
||||
describe("OAuth credential adoption is identity-gated", () => {
|
||||
const envSnapshot = captureEnv(["OPENCLAW_STATE_DIR"]);
|
||||
const envSnapshot = captureEnv([
|
||||
"OPENCLAW_STATE_DIR",
|
||||
"OPENCLAW_AGENT_DIR",
|
||||
"PI_CODING_AGENT_DIR",
|
||||
]);
|
||||
let tempRoot = "";
|
||||
let mainAgentDir = "";
|
||||
|
||||
@@ -88,6 +118,8 @@ describe("OAuth credential adoption is identity-gated", () => {
|
||||
tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-oauth-adopt-identity-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempRoot;
|
||||
mainAgentDir = path.join(tempRoot, "agents", "main", "agent");
|
||||
process.env.OPENCLAW_AGENT_DIR = mainAgentDir;
|
||||
process.env.PI_CODING_AGENT_DIR = mainAgentDir;
|
||||
await fs.mkdir(mainAgentDir, { recursive: true });
|
||||
await loadOAuthModuleForTest();
|
||||
resetOAuthRefreshQueuesForTest();
|
||||
@@ -143,7 +175,7 @@ describe("OAuth credential adoption is identity-gated", () => {
|
||||
mainAgentDir,
|
||||
);
|
||||
|
||||
const result = await resolveApiKeyForProfile({
|
||||
const result = await resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(subAgentDir),
|
||||
profileId,
|
||||
agentDir: subAgentDir,
|
||||
@@ -212,7 +244,7 @@ describe("OAuth credential adoption is identity-gated", () => {
|
||||
}) as never,
|
||||
);
|
||||
|
||||
const result = await resolveApiKeyForProfile({
|
||||
const result = await resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(subAgentDir),
|
||||
profileId,
|
||||
agentDir: subAgentDir,
|
||||
@@ -274,7 +306,7 @@ describe("OAuth credential adoption is identity-gated", () => {
|
||||
mainAgentDir,
|
||||
);
|
||||
|
||||
const result = await resolveApiKeyForProfile({
|
||||
const result = await resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(subAgentDir),
|
||||
profileId,
|
||||
agentDir: subAgentDir,
|
||||
@@ -331,7 +363,7 @@ describe("OAuth credential adoption is identity-gated", () => {
|
||||
|
||||
// Plugin refresh must NOT be called — sub should adopt main's fresh
|
||||
// cred rather than performing its own refresh.
|
||||
const result = await resolveApiKeyForProfile({
|
||||
const result = await resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(subAgentDir),
|
||||
profileId,
|
||||
agentDir: subAgentDir,
|
||||
@@ -380,7 +412,7 @@ describe("OAuth credential adoption is identity-gated", () => {
|
||||
mainAgentDir,
|
||||
);
|
||||
|
||||
const result = await resolveApiKeyForProfile({
|
||||
const result = await resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(subAgentDir),
|
||||
profileId,
|
||||
agentDir: subAgentDir,
|
||||
@@ -444,7 +476,7 @@ describe("OAuth credential adoption is identity-gated", () => {
|
||||
}) as never,
|
||||
);
|
||||
|
||||
const result = await resolveApiKeyForProfile({
|
||||
const result = await resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(subAgentDir),
|
||||
profileId,
|
||||
agentDir: subAgentDir,
|
||||
@@ -511,7 +543,7 @@ describe("OAuth credential adoption is identity-gated", () => {
|
||||
// Catch-block main-inherit must refuse the non-overlapping cred and
|
||||
// propagate the original error rather than leaking main's credential.
|
||||
await expect(
|
||||
resolveApiKeyForProfile({
|
||||
resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(subAgentDir),
|
||||
profileId,
|
||||
agentDir: subAgentDir,
|
||||
@@ -574,7 +606,7 @@ describe("OAuth credential adoption is identity-gated", () => {
|
||||
throw new Error("upstream 503 service unavailable");
|
||||
});
|
||||
|
||||
const result = await resolveApiKeyForProfile({
|
||||
const result = await resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(subAgentDir),
|
||||
profileId,
|
||||
agentDir: subAgentDir,
|
||||
@@ -643,7 +675,7 @@ describe("OAuth credential adoption is identity-gated", () => {
|
||||
});
|
||||
|
||||
await expect(
|
||||
resolveApiKeyForProfile({
|
||||
resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(subAgentDir),
|
||||
profileId,
|
||||
agentDir: subAgentDir,
|
||||
|
||||
@@ -18,6 +18,12 @@ async function loadOAuthModuleForTest() {
|
||||
({ resolveApiKeyForProfile, resetOAuthRefreshQueuesForTest } = await import("./oauth.js"));
|
||||
}
|
||||
|
||||
function resolveApiKeyForProfileInTest(
|
||||
params: Omit<Parameters<typeof resolveApiKeyForProfile>[0], "cfg">,
|
||||
) {
|
||||
return resolveApiKeyForProfile({ cfg: {}, ...params });
|
||||
}
|
||||
|
||||
const {
|
||||
refreshProviderOAuthCredentialWithPluginMock,
|
||||
formatProviderAuthProfileApiKeyWithPluginMock,
|
||||
@@ -35,12 +41,22 @@ vi.mock("../cli-credentials.js", () => ({
|
||||
writeCodexCliCredentials: () => true,
|
||||
}));
|
||||
|
||||
vi.mock("@mariozechner/pi-ai/oauth", () => ({
|
||||
getOAuthApiKey: vi.fn(async () => null),
|
||||
getOAuthProviders: () => [{ id: "openai-codex" }],
|
||||
}));
|
||||
|
||||
vi.mock("../../plugins/provider-runtime.runtime.js", () => ({
|
||||
formatProviderAuthProfileApiKeyWithPlugin: (params: { context?: { access?: string } }) =>
|
||||
formatProviderAuthProfileApiKeyWithPluginMock() ?? params?.context?.access,
|
||||
refreshProviderOAuthCredentialWithPlugin: refreshProviderOAuthCredentialWithPluginMock,
|
||||
}));
|
||||
|
||||
vi.mock("./external-auth.js", () => ({
|
||||
overlayExternalAuthProfiles: <T>(store: T) => store,
|
||||
shouldPersistExternalAuthProfile: () => true,
|
||||
}));
|
||||
|
||||
vi.mock("./doctor.js", () => ({
|
||||
formatAuthDoctorHint: async () => undefined,
|
||||
}));
|
||||
@@ -79,7 +95,11 @@ function createExpiredOauthStore(params: {
|
||||
}
|
||||
|
||||
describe("resolveApiKeyForProfile cross-agent refresh coordination (#26322)", () => {
|
||||
const envSnapshot = captureEnv(["OPENCLAW_STATE_DIR"]);
|
||||
const envSnapshot = captureEnv([
|
||||
"OPENCLAW_STATE_DIR",
|
||||
"OPENCLAW_AGENT_DIR",
|
||||
"PI_CODING_AGENT_DIR",
|
||||
]);
|
||||
let tempRoot = "";
|
||||
let mainAgentDir = "";
|
||||
|
||||
@@ -93,6 +113,8 @@ describe("resolveApiKeyForProfile cross-agent refresh coordination (#26322)", ()
|
||||
tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-oauth-concurrent-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempRoot;
|
||||
mainAgentDir = path.join(tempRoot, "agents", "main", "agent");
|
||||
process.env.OPENCLAW_AGENT_DIR = mainAgentDir;
|
||||
process.env.PI_CODING_AGENT_DIR = mainAgentDir;
|
||||
await fs.mkdir(mainAgentDir, { recursive: true });
|
||||
await loadOAuthModuleForTest();
|
||||
// Drop any refresh-queue entries left behind by a prior timed-out test.
|
||||
@@ -150,7 +172,7 @@ describe("resolveApiKeyForProfile cross-agent refresh coordination (#26322)", ()
|
||||
// performed; the remaining 19 adopt the resulting fresh credentials.
|
||||
const results = await Promise.all(
|
||||
subAgents.map((agentDir) =>
|
||||
resolveApiKeyForProfile({
|
||||
resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(agentDir),
|
||||
profileId,
|
||||
agentDir,
|
||||
@@ -165,6 +187,5 @@ describe("resolveApiKeyForProfile cross-agent refresh coordination (#26322)", ()
|
||||
expect(result?.apiKey).toBe("cross-agent-refreshed-access");
|
||||
expect(result?.provider).toBe(provider);
|
||||
}
|
||||
}, // Generous timeout; the fix should complete well under 5s in practice.
|
||||
60_000);
|
||||
}, 60_000); // Generous timeout; the fix should complete well under 5s in practice.
|
||||
});
|
||||
|
||||
@@ -19,6 +19,12 @@ async function loadOAuthModuleForTest() {
|
||||
({ resolveApiKeyForProfile, resetOAuthRefreshQueuesForTest } = await import("./oauth.js"));
|
||||
}
|
||||
|
||||
function resolveApiKeyForProfileInTest(
|
||||
params: Omit<Parameters<typeof resolveApiKeyForProfile>[0], "cfg">,
|
||||
) {
|
||||
return resolveApiKeyForProfile({ cfg: {}, ...params });
|
||||
}
|
||||
|
||||
const {
|
||||
refreshProviderOAuthCredentialWithPluginMock,
|
||||
formatProviderAuthProfileApiKeyWithPluginMock,
|
||||
@@ -55,6 +61,16 @@ vi.mock("../../plugins/provider-runtime.runtime.js", () => ({
|
||||
refreshProviderOAuthCredentialWithPlugin: refreshProviderOAuthCredentialWithPluginMock,
|
||||
}));
|
||||
|
||||
vi.mock("../../infra/file-lock.js", () => ({
|
||||
resetFileLockStateForTest: () => undefined,
|
||||
withFileLock: async <T>(_filePath: string, _options: unknown, run: () => Promise<T>) => run(),
|
||||
}));
|
||||
|
||||
vi.mock("../../plugin-sdk/file-lock.js", () => ({
|
||||
resetFileLockStateForTest: () => undefined,
|
||||
withFileLock: async <T>(_filePath: string, _options: unknown, run: () => Promise<T>) => run(),
|
||||
}));
|
||||
|
||||
vi.mock("./doctor.js", () => ({
|
||||
formatAuthDoctorHint: async () => undefined,
|
||||
}));
|
||||
@@ -90,7 +106,11 @@ function createExpiredOauthStore(params: {
|
||||
}
|
||||
|
||||
describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () => {
|
||||
const envSnapshot = captureEnv(["OPENCLAW_STATE_DIR"]);
|
||||
const envSnapshot = captureEnv([
|
||||
"OPENCLAW_STATE_DIR",
|
||||
"OPENCLAW_AGENT_DIR",
|
||||
"PI_CODING_AGENT_DIR",
|
||||
]);
|
||||
let tempRoot = "";
|
||||
let mainAgentDir = "";
|
||||
|
||||
@@ -105,6 +125,8 @@ describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () =>
|
||||
tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-oauth-mirror-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempRoot;
|
||||
mainAgentDir = path.join(tempRoot, "agents", "main", "agent");
|
||||
process.env.OPENCLAW_AGENT_DIR = mainAgentDir;
|
||||
process.env.PI_CODING_AGENT_DIR = mainAgentDir;
|
||||
await fs.mkdir(mainAgentDir, { recursive: true });
|
||||
await loadOAuthModuleForTest();
|
||||
resetOAuthRefreshQueuesForTest();
|
||||
@@ -146,7 +168,7 @@ describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () =>
|
||||
}) as never,
|
||||
);
|
||||
|
||||
const result = await resolveApiKeyForProfile({
|
||||
const result = await resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(subAgentDir),
|
||||
profileId,
|
||||
agentDir: subAgentDir,
|
||||
@@ -190,7 +212,7 @@ describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () =>
|
||||
// Main-agent refresh uses undefined agentDir; the mirror path is a no-op
|
||||
// (local == main). Just make sure the main store still reflects the refresh
|
||||
// and no double-write happens.
|
||||
const result = await resolveApiKeyForProfile({
|
||||
const result = await resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(undefined),
|
||||
profileId,
|
||||
agentDir: undefined,
|
||||
@@ -244,7 +266,7 @@ describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () =>
|
||||
}) as never,
|
||||
);
|
||||
|
||||
const result = await resolveApiKeyForProfile({
|
||||
const result = await resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(subAgentDir),
|
||||
profileId,
|
||||
agentDir: subAgentDir,
|
||||
@@ -310,7 +332,7 @@ describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () =>
|
||||
}) as never,
|
||||
);
|
||||
|
||||
const result = await resolveApiKeyForProfile({
|
||||
const result = await resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(subAgentDir),
|
||||
profileId,
|
||||
agentDir: subAgentDir,
|
||||
@@ -375,7 +397,7 @@ describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () =>
|
||||
// The sub-agent will actually adopt main's fresher creds via the inside-
|
||||
// lock recheck (that's the whole point of #26322), so refresh may not
|
||||
// even fire. We only care that the main store is not regressed.
|
||||
await resolveApiKeyForProfile({
|
||||
await resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(subAgentDir),
|
||||
profileId,
|
||||
agentDir: subAgentDir,
|
||||
@@ -431,7 +453,7 @@ describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () =>
|
||||
}) as never,
|
||||
);
|
||||
|
||||
const result = await resolveApiKeyForProfile({
|
||||
const result = await resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(subAgentDir),
|
||||
profileId,
|
||||
agentDir: subAgentDir,
|
||||
@@ -489,7 +511,7 @@ describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () =>
|
||||
}) as never,
|
||||
);
|
||||
|
||||
await resolveApiKeyForProfile({
|
||||
await resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(subAgentDir),
|
||||
profileId,
|
||||
agentDir: subAgentDir,
|
||||
@@ -538,7 +560,7 @@ describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () =>
|
||||
|
||||
// Refresh mock intentionally left as default-undefined — it should not
|
||||
// be called, the pre-refresh adopt wins.
|
||||
const result = await resolveApiKeyForProfile({
|
||||
const result = await resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(subAgentDir),
|
||||
profileId,
|
||||
agentDir: subAgentDir,
|
||||
@@ -601,7 +623,7 @@ describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () =>
|
||||
throw new Error("upstream 503 service unavailable");
|
||||
});
|
||||
|
||||
const result = await resolveApiKeyForProfile({
|
||||
const result = await resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(subAgentDir),
|
||||
profileId,
|
||||
agentDir: subAgentDir,
|
||||
@@ -665,7 +687,7 @@ describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () =>
|
||||
}) as never,
|
||||
);
|
||||
|
||||
const result = await resolveApiKeyForProfile({
|
||||
const result = await resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(subAgentDir),
|
||||
profileId,
|
||||
agentDir: subAgentDir,
|
||||
@@ -723,7 +745,7 @@ describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () =>
|
||||
}) as never,
|
||||
);
|
||||
|
||||
await resolveApiKeyForProfile({
|
||||
await resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(subAgentDir),
|
||||
profileId,
|
||||
agentDir: subAgentDir,
|
||||
@@ -763,7 +785,7 @@ describe("resolveApiKeyForProfile OAuth refresh mirror-to-main (#26322)", () =>
|
||||
}) as never,
|
||||
);
|
||||
|
||||
const result = await resolveApiKeyForProfile({
|
||||
const result = await resolveApiKeyForProfileInTest({
|
||||
store: ensureAuthProfileStore(subAgentDir),
|
||||
profileId,
|
||||
agentDir: subAgentDir,
|
||||
|
||||
@@ -23,6 +23,11 @@ vi.mock("../../plugins/manifest-registry.js", () => ({
|
||||
loadPluginManifestRegistry,
|
||||
}));
|
||||
|
||||
vi.mock("./external-auth.js", () => ({
|
||||
overlayExternalAuthProfiles: <T>(store: T) => store,
|
||||
shouldPersistExternalAuthProfile: () => true,
|
||||
}));
|
||||
|
||||
describe("resolveAuthProfileOrder", () => {
|
||||
beforeEach(() => {
|
||||
loadPluginManifestRegistry.mockClear();
|
||||
|
||||
Reference in New Issue
Block a user