Spaces:
Paused
Paused
OpenClawBot / src /agents /auth-profiles.resolve-auth-profile-order.does-not-prioritize-lastgood-round-robin-ordering.test.ts
| import { describe, expect, it } from "vitest"; | |
| import { resolveAuthProfileOrder } from "./auth-profiles.js"; | |
| describe("resolveAuthProfileOrder", () => { | |
| const store: AuthProfileStore = { | |
| version: 1, | |
| profiles: { | |
| "anthropic:default": { | |
| type: "api_key", | |
| provider: "anthropic", | |
| key: "sk-default", | |
| }, | |
| "anthropic:work": { | |
| type: "api_key", | |
| provider: "anthropic", | |
| key: "sk-work", | |
| }, | |
| }, | |
| }; | |
| const cfg = { | |
| auth: { | |
| profiles: { | |
| "anthropic:default": { provider: "anthropic", mode: "api_key" }, | |
| "anthropic:work": { provider: "anthropic", mode: "api_key" }, | |
| }, | |
| }, | |
| }; | |
| it("does not prioritize lastGood over round-robin ordering", () => { | |
| const order = resolveAuthProfileOrder({ | |
| cfg, | |
| store: { | |
| ...store, | |
| lastGood: { anthropic: "anthropic:work" }, | |
| usageStats: { | |
| "anthropic:default": { lastUsed: 100 }, | |
| "anthropic:work": { lastUsed: 200 }, | |
| }, | |
| }, | |
| provider: "anthropic", | |
| }); | |
| expect(order[0]).toBe("anthropic:default"); | |
| }); | |
| it("uses explicit profiles when order is missing", () => { | |
| const order = resolveAuthProfileOrder({ | |
| cfg, | |
| store, | |
| provider: "anthropic", | |
| }); | |
| expect(order).toEqual(["anthropic:default", "anthropic:work"]); | |
| }); | |
| it("uses configured order when provided", () => { | |
| const order = resolveAuthProfileOrder({ | |
| cfg: { | |
| auth: { | |
| order: { anthropic: ["anthropic:work", "anthropic:default"] }, | |
| profiles: cfg.auth.profiles, | |
| }, | |
| }, | |
| store, | |
| provider: "anthropic", | |
| }); | |
| expect(order).toEqual(["anthropic:work", "anthropic:default"]); | |
| }); | |
| it("prefers store order over config order", () => { | |
| const order = resolveAuthProfileOrder({ | |
| cfg: { | |
| auth: { | |
| order: { anthropic: ["anthropic:default", "anthropic:work"] }, | |
| profiles: cfg.auth.profiles, | |
| }, | |
| }, | |
| store: { | |
| ...store, | |
| order: { anthropic: ["anthropic:work", "anthropic:default"] }, | |
| }, | |
| provider: "anthropic", | |
| }); | |
| expect(order).toEqual(["anthropic:work", "anthropic:default"]); | |
| }); | |
| it("pushes cooldown profiles to the end even with store order", () => { | |
| const now = Date.now(); | |
| const order = resolveAuthProfileOrder({ | |
| store: { | |
| ...store, | |
| order: { anthropic: ["anthropic:default", "anthropic:work"] }, | |
| usageStats: { | |
| "anthropic:default": { cooldownUntil: now + 60_000 }, | |
| "anthropic:work": { lastUsed: 1 }, | |
| }, | |
| }, | |
| provider: "anthropic", | |
| }); | |
| expect(order).toEqual(["anthropic:work", "anthropic:default"]); | |
| }); | |
| it("pushes cooldown profiles to the end even with configured order", () => { | |
| const now = Date.now(); | |
| const order = resolveAuthProfileOrder({ | |
| cfg: { | |
| auth: { | |
| order: { anthropic: ["anthropic:default", "anthropic:work"] }, | |
| profiles: cfg.auth.profiles, | |
| }, | |
| }, | |
| store: { | |
| ...store, | |
| usageStats: { | |
| "anthropic:default": { cooldownUntil: now + 60_000 }, | |
| "anthropic:work": { lastUsed: 1 }, | |
| }, | |
| }, | |
| provider: "anthropic", | |
| }); | |
| expect(order).toEqual(["anthropic:work", "anthropic:default"]); | |
| }); | |
| it("pushes disabled profiles to the end even with store order", () => { | |
| const now = Date.now(); | |
| const order = resolveAuthProfileOrder({ | |
| store: { | |
| ...store, | |
| order: { anthropic: ["anthropic:default", "anthropic:work"] }, | |
| usageStats: { | |
| "anthropic:default": { | |
| disabledUntil: now + 60_000, | |
| disabledReason: "billing", | |
| }, | |
| "anthropic:work": { lastUsed: 1 }, | |
| }, | |
| }, | |
| provider: "anthropic", | |
| }); | |
| expect(order).toEqual(["anthropic:work", "anthropic:default"]); | |
| }); | |
| it("pushes disabled profiles to the end even with configured order", () => { | |
| const now = Date.now(); | |
| const order = resolveAuthProfileOrder({ | |
| cfg: { | |
| auth: { | |
| order: { anthropic: ["anthropic:default", "anthropic:work"] }, | |
| profiles: cfg.auth.profiles, | |
| }, | |
| }, | |
| store: { | |
| ...store, | |
| usageStats: { | |
| "anthropic:default": { | |
| disabledUntil: now + 60_000, | |
| disabledReason: "billing", | |
| }, | |
| "anthropic:work": { lastUsed: 1 }, | |
| }, | |
| }, | |
| provider: "anthropic", | |
| }); | |
| expect(order).toEqual(["anthropic:work", "anthropic:default"]); | |
| }); | |
| it("mode: oauth config accepts both oauth and token credentials (issue #559)", () => { | |
| const now = Date.now(); | |
| const storeWithBothTypes: AuthProfileStore = { | |
| version: 1, | |
| profiles: { | |
| "anthropic:oauth-cred": { | |
| type: "oauth", | |
| provider: "anthropic", | |
| access: "access-token", | |
| refresh: "refresh-token", | |
| expires: now + 60_000, | |
| }, | |
| "anthropic:token-cred": { | |
| type: "token", | |
| provider: "anthropic", | |
| token: "just-a-token", | |
| expires: now + 60_000, | |
| }, | |
| }, | |
| }; | |
| const orderOauthCred = resolveAuthProfileOrder({ | |
| store: storeWithBothTypes, | |
| provider: "anthropic", | |
| cfg: { | |
| auth: { | |
| profiles: { | |
| "anthropic:oauth-cred": { provider: "anthropic", mode: "oauth" }, | |
| }, | |
| }, | |
| }, | |
| }); | |
| expect(orderOauthCred).toContain("anthropic:oauth-cred"); | |
| const orderTokenCred = resolveAuthProfileOrder({ | |
| store: storeWithBothTypes, | |
| provider: "anthropic", | |
| cfg: { | |
| auth: { | |
| profiles: { | |
| "anthropic:token-cred": { provider: "anthropic", mode: "oauth" }, | |
| }, | |
| }, | |
| }, | |
| }); | |
| expect(orderTokenCred).toContain("anthropic:token-cred"); | |
| }); | |
| it("mode: token config rejects oauth credentials (issue #559 root cause)", () => { | |
| const now = Date.now(); | |
| const storeWithOauth: AuthProfileStore = { | |
| version: 1, | |
| profiles: { | |
| "anthropic:oauth-cred": { | |
| type: "oauth", | |
| provider: "anthropic", | |
| access: "access-token", | |
| refresh: "refresh-token", | |
| expires: now + 60_000, | |
| }, | |
| }, | |
| }; | |
| const order = resolveAuthProfileOrder({ | |
| store: storeWithOauth, | |
| provider: "anthropic", | |
| cfg: { | |
| auth: { | |
| profiles: { | |
| "anthropic:oauth-cred": { provider: "anthropic", mode: "token" }, | |
| }, | |
| }, | |
| }, | |
| }); | |
| expect(order).not.toContain("anthropic:oauth-cred"); | |
| }); | |
| }); | |