readiness.spec.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. /** Pure official-DeepSeek readiness projection over the shared Models join. */
  2. import { describe, expect, it } from 'vitest'
  3. import type { CredentialView } from '@deepseek-ai/dsh-client-connection/client'
  4. import type { ModelsSettingsState, ProviderRow } from '../src/client/store.ts'
  5. import { deepSeekReadiness } from '../src/client/store.ts'
  6. const missingCredential: CredentialView = { configured: false, writable: true }
  7. function row(overrides: Partial<ProviderRow> = {}): ProviderRow {
  8. return {
  9. entry: {
  10. provider: 'deepseek-official',
  11. displayName: 'DeepSeek',
  12. settingsNs: 'llm-deepseek',
  13. settingsPath: [],
  14. active: true,
  15. },
  16. configured: true,
  17. removable: false,
  18. apiKeyEnv: 'DEEPSEEK_API_KEY',
  19. credential: missingCredential,
  20. literalApiKeyConfigured: false,
  21. ...overrides,
  22. }
  23. }
  24. function state(overrides: Partial<ModelsSettingsState> = {}): ModelsSettingsState {
  25. return {
  26. status: 'ready',
  27. error: null,
  28. credentialError: null,
  29. writable: true,
  30. rows: [row()],
  31. namespaces: new Map(),
  32. ...overrides,
  33. }
  34. }
  35. describe('deepSeekReadiness', () => {
  36. it('waits for the first join and skips onboarding when the adapter directory entry is absent', () => {
  37. expect(deepSeekReadiness(state({ status: 'idle', rows: [] }))).toEqual({ kind: 'loading' })
  38. expect(deepSeekReadiness(state({ status: 'loading', rows: [] }))).toEqual({ kind: 'loading' })
  39. expect(deepSeekReadiness(state({ rows: [] }))).toEqual({ kind: 'adapter-absent' })
  40. expect(deepSeekReadiness(state({
  41. rows: [row({
  42. entry: {
  43. ...row().entry,
  44. settingsNs: '',
  45. },
  46. })],
  47. }))).toEqual({ kind: 'adapter-absent' })
  48. })
  49. it('reports a missing writable effective credential', () => {
  50. expect(deepSeekReadiness(state())).toEqual({ kind: 'credential-missing' })
  51. })
  52. it('accepts file and process-environment credentials without prompting', () => {
  53. expect(deepSeekReadiness(state({
  54. rows: [row({ credential: { configured: true, source: 'file', writable: true } })],
  55. }))).toEqual({ kind: 'configured' })
  56. expect(deepSeekReadiness(state({
  57. rows: [row({ credential: { configured: true, source: 'env', writable: false } })],
  58. }))).toEqual({ kind: 'configured' })
  59. })
  60. it('accepts the redacted literal-key sidecar before judging the credential domain', () => {
  61. expect(deepSeekReadiness(state({
  62. credentialError: 'credentials service absent',
  63. rows: [row({ literalApiKeyConfigured: true, credential: undefined })],
  64. }))).toEqual({ kind: 'configured' })
  65. })
  66. it('turns missing capabilities and inconsistent descriptors into diagnostics', () => {
  67. expect(deepSeekReadiness(state({ status: 'error', error: 'settings down' }))).toEqual({
  68. kind: 'unavailable',
  69. reason: 'load-failed',
  70. })
  71. expect(deepSeekReadiness(state({
  72. rows: [row({ entry: { ...row().entry, active: false } })],
  73. }))).toEqual({ kind: 'unavailable', reason: 'provider-inactive' })
  74. expect(deepSeekReadiness(state({
  75. rows: [row({ configured: false })],
  76. }))).toEqual({ kind: 'unavailable', reason: 'settings-unavailable' })
  77. expect(deepSeekReadiness(state({
  78. rows: [row({ apiKeyEnv: undefined })],
  79. }))).toEqual({ kind: 'unavailable', reason: 'credential-ref-unavailable' })
  80. expect(deepSeekReadiness(state({
  81. credentialError: 'credentials service is absent',
  82. }))).toEqual({
  83. kind: 'unavailable',
  84. reason: 'credentials-unavailable',
  85. })
  86. expect(deepSeekReadiness(state({
  87. rows: [row({ credential: undefined })],
  88. }))).toEqual({ kind: 'unavailable', reason: 'credentials-unavailable' })
  89. expect(deepSeekReadiness(state({
  90. rows: [row({ credential: { configured: false, writable: false } })],
  91. }))).toEqual({ kind: 'unavailable', reason: 'credential-read-only' })
  92. expect(deepSeekReadiness(state({ writable: false }))).toEqual({
  93. kind: 'unavailable',
  94. reason: 'settings-read-only',
  95. })
  96. })
  97. })