108 lines
3.7 KiB
TypeScript
108 lines
3.7 KiB
TypeScript
import { afterAll, afterEach, beforeAll, describe, expect, it } from "bun:test"
|
|
import { mkdirSync, rmSync, writeFileSync } from "node:fs"
|
|
import { tmpdir } from "node:os"
|
|
import * as path from "node:path"
|
|
|
|
import {
|
|
_resetProviderAuthCacheForTesting,
|
|
getProviderAuthType,
|
|
isProviderUsingOAuth,
|
|
} from "./opencode-provider-auth"
|
|
|
|
describe("opencode-provider-auth", () => {
|
|
let tempDataDir: string
|
|
const originalXdgDataHome = process.env.XDG_DATA_HOME
|
|
|
|
function writeAuthFile(contents: string): void {
|
|
const opencodeDir = path.join(tempDataDir, "opencode")
|
|
mkdirSync(opencodeDir, { recursive: true })
|
|
writeFileSync(path.join(opencodeDir, "auth.json"), contents, "utf-8")
|
|
_resetProviderAuthCacheForTesting()
|
|
}
|
|
|
|
beforeAll(() => {
|
|
tempDataDir = path.join(tmpdir(), `opencode-provider-auth-${Date.now()}-${Math.random().toString(36).slice(2)}`)
|
|
mkdirSync(tempDataDir, { recursive: true })
|
|
process.env.XDG_DATA_HOME = tempDataDir
|
|
})
|
|
|
|
afterAll(() => {
|
|
if (originalXdgDataHome === undefined) {
|
|
delete process.env.XDG_DATA_HOME
|
|
} else {
|
|
process.env.XDG_DATA_HOME = originalXdgDataHome
|
|
}
|
|
rmSync(tempDataDir, { recursive: true, force: true })
|
|
_resetProviderAuthCacheForTesting()
|
|
})
|
|
|
|
afterEach(() => {
|
|
_resetProviderAuthCacheForTesting()
|
|
})
|
|
|
|
it("#given auth.json with oauth entry #then detects OAuth for that provider", () => {
|
|
// given auth.json where anthropic is OAuth
|
|
writeAuthFile(JSON.stringify({
|
|
anthropic: { type: "oauth", refresh: "r", access: "a", expires: 1 },
|
|
opencode: { type: "api", key: "sk-x" },
|
|
}))
|
|
|
|
// when isProviderUsingOAuth queries each provider
|
|
const anthropicOauth = isProviderUsingOAuth("anthropic")
|
|
const opencodeOauth = isProviderUsingOAuth("opencode")
|
|
|
|
// then only OAuth providers return true
|
|
expect(anthropicOauth).toBe(true)
|
|
expect(opencodeOauth).toBe(false)
|
|
})
|
|
|
|
it("#given api-key auth.json entry #then returns the api auth type", () => {
|
|
// given auth.json with an API key for anthropic
|
|
writeAuthFile(JSON.stringify({ anthropic: { type: "api", key: "sk-ant-xxx" } }))
|
|
|
|
// when getProviderAuthType queries the provider
|
|
const authType = getProviderAuthType("anthropic")
|
|
|
|
// then the api type is returned
|
|
expect(authType).toBe("api")
|
|
expect(isProviderUsingOAuth("anthropic")).toBe(false)
|
|
})
|
|
|
|
it("#given missing auth.json #then returns undefined with no throw", () => {
|
|
// given no auth.json exists (XDG_DATA_HOME points to an empty dir)
|
|
rmSync(path.join(tempDataDir, "opencode"), { recursive: true, force: true })
|
|
_resetProviderAuthCacheForTesting()
|
|
|
|
// when isProviderUsingOAuth queries a provider
|
|
const anthropicOauth = isProviderUsingOAuth("anthropic")
|
|
const anthropicType = getProviderAuthType("anthropic")
|
|
|
|
// then callers get a safe undefined/false
|
|
expect(anthropicOauth).toBe(false)
|
|
expect(anthropicType).toBeUndefined()
|
|
})
|
|
|
|
it("#given malformed auth.json #then does not throw and returns undefined", () => {
|
|
// given a malformed JSON auth file
|
|
writeAuthFile("not json at all")
|
|
|
|
// when isProviderUsingOAuth queries a provider
|
|
const anthropicOauth = isProviderUsingOAuth("anthropic")
|
|
|
|
// then detection degrades safely
|
|
expect(anthropicOauth).toBe(false)
|
|
})
|
|
|
|
it("#given unknown provider #then returns undefined", () => {
|
|
// given auth.json without an entry for the queried provider
|
|
writeAuthFile(JSON.stringify({ anthropic: { type: "oauth", refresh: "r", access: "a", expires: 1 } }))
|
|
|
|
// when querying a provider that is not present
|
|
const openai = getProviderAuthType("openai")
|
|
|
|
// then undefined
|
|
expect(openai).toBeUndefined()
|
|
expect(isProviderUsingOAuth("openai")).toBe(false)
|
|
})
|
|
})
|