mirror of
https://github.com/langgenius/dify.git
synced 2026-05-29 21:27:54 +08:00
Co-authored-by: GareArc <garethcxy@dify.ai> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: L1nSn0w <l1nsn0w@qq.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: gigglewang <gigglewang@dify.ai> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> Co-authored-by: Xiyuan Chen <52963600+GareArc@users.noreply.github.com>
76 lines
2.3 KiB
TypeScript
76 lines
2.3 KiB
TypeScript
import type { TokenStore } from './store.js'
|
|
import { describe, expect, it, vi } from 'vitest'
|
|
import { selectStore } from './store.js'
|
|
|
|
function memBackend(label: string): TokenStore & { _label: string } {
|
|
const map = new Map<string, string>()
|
|
const k = (h: string, a: string) => `${h}::${a}`
|
|
return {
|
|
_label: label,
|
|
async put(h, a, t) { map.set(k(h, a), t) },
|
|
async get(h, a) { return map.get(k(h, a)) },
|
|
async delete(h, a) { map.delete(k(h, a)) },
|
|
async list() { return [] },
|
|
}
|
|
}
|
|
|
|
describe('selectStore', () => {
|
|
it('returns keychain when probe succeeds', async () => {
|
|
const k = memBackend('keyring')
|
|
const f = memBackend('file')
|
|
const result = await selectStore({
|
|
configDir: '/tmp/x',
|
|
factory: { keyring: () => k, file: () => f },
|
|
})
|
|
expect(result.mode).toBe('keychain')
|
|
expect(result.store).toBe(k)
|
|
})
|
|
|
|
it('falls back to file when keyring put throws', async () => {
|
|
const k = memBackend('keyring')
|
|
const f = memBackend('file')
|
|
k.put = vi.fn().mockRejectedValue(new Error('locked'))
|
|
const result = await selectStore({
|
|
configDir: '/tmp/x',
|
|
factory: { keyring: () => k, file: () => f },
|
|
})
|
|
expect(result.mode).toBe('file')
|
|
expect(result.store).toBe(f)
|
|
})
|
|
|
|
it('falls back to file when probe round-trip mismatches', async () => {
|
|
const k = memBackend('keyring')
|
|
const f = memBackend('file')
|
|
k.get = vi.fn().mockResolvedValue('something-else')
|
|
const result = await selectStore({
|
|
configDir: '/tmp/x',
|
|
factory: { keyring: () => k, file: () => f },
|
|
})
|
|
expect(result.mode).toBe('file')
|
|
expect(result.store).toBe(f)
|
|
})
|
|
|
|
it('falls back to file when keyring constructor throws', async () => {
|
|
const f = memBackend('file')
|
|
const result = await selectStore({
|
|
configDir: '/tmp/x',
|
|
factory: {
|
|
keyring: () => { throw new Error('no backend') },
|
|
file: () => f,
|
|
},
|
|
})
|
|
expect(result.mode).toBe('file')
|
|
expect(result.store).toBe(f)
|
|
})
|
|
|
|
it('cleans up probe entry after successful probe', async () => {
|
|
const k = memBackend('keyring')
|
|
const f = memBackend('file')
|
|
await selectStore({
|
|
configDir: '/tmp/x',
|
|
factory: { keyring: () => k, file: () => f },
|
|
})
|
|
expect(await k.get('__difyctl_probe__', '__probe__')).toBeUndefined()
|
|
})
|
|
})
|