125 lines
4.5 KiB
TypeScript
125 lines
4.5 KiB
TypeScript
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'
|
|
import { tmpdir } from 'node:os'
|
|
import { join } from 'node:path'
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import * as z from 'zod'
|
|
import { readConfigFile, readEnvConnections } from '../../../src/config/sources.js'
|
|
import type { StoreOptions } from '../../../src/config/store.js'
|
|
|
|
const schema = z.object({ name: z.string(), value: z.number() }).strict()
|
|
const opts: StoreOptions = { logLabel: 'testlabel' }
|
|
const conn = { name: 'a', value: 1 }
|
|
|
|
describe('readEnvConnections', () => {
|
|
let errSpy: ReturnType<typeof vi.spyOn>
|
|
|
|
beforeEach(() => {
|
|
errSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
|
|
})
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks()
|
|
})
|
|
|
|
it('returns empty when the env var is unset', () => {
|
|
expect(readEnvConnections(schema, {}, 'X_CONNECTIONS', opts)).toEqual([])
|
|
expect(errSpy).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('parses a JSON array of connections', () => {
|
|
const env = { X_CONNECTIONS: JSON.stringify([conn]) }
|
|
expect(readEnvConnections(schema, env, 'X_CONNECTIONS', opts)).toEqual([conn])
|
|
})
|
|
|
|
it('ignores invalid JSON and logs with the label and var name', () => {
|
|
expect(
|
|
readEnvConnections(schema, { X_CONNECTIONS: 'nope{' }, 'X_CONNECTIONS', opts)
|
|
).toEqual([])
|
|
expect(errSpy).toHaveBeenCalledWith('testlabel: X_CONNECTIONS is not valid JSON, ignoring')
|
|
})
|
|
|
|
it('ignores non-array JSON and logs with the label and var name', () => {
|
|
expect(readEnvConnections(schema, { X_CONNECTIONS: '{}' }, 'X_CONNECTIONS', opts)).toEqual(
|
|
[]
|
|
)
|
|
expect(errSpy).toHaveBeenCalledWith(
|
|
'testlabel: X_CONNECTIONS must be a JSON array, ignoring'
|
|
)
|
|
})
|
|
})
|
|
|
|
describe('readConfigFile', () => {
|
|
let dir: string
|
|
let errSpy: ReturnType<typeof vi.spyOn>
|
|
|
|
beforeEach(() => {
|
|
dir = mkdtempSync(join(tmpdir(), 'core-config-'))
|
|
errSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
|
|
})
|
|
|
|
afterEach(() => {
|
|
rmSync(dir, { recursive: true, force: true })
|
|
vi.restoreAllMocks()
|
|
})
|
|
|
|
it('returns empty when path is undefined', () => {
|
|
expect(readConfigFile(schema, undefined, opts)).toEqual([])
|
|
expect(errSpy).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('warns and returns empty for a missing file', () => {
|
|
const path = join(dir, 'absent.json')
|
|
expect(readConfigFile(schema, path, opts)).toEqual([])
|
|
expect(errSpy).toHaveBeenCalledWith(
|
|
'testlabel: config file ' + path + ' not found, ignoring'
|
|
)
|
|
})
|
|
|
|
it('reads the { connections: [...] } shape', () => {
|
|
const path = join(dir, 'config.json')
|
|
writeFileSync(path, JSON.stringify({ connections: [conn] }))
|
|
expect(readConfigFile(schema, path, opts)).toEqual([conn])
|
|
})
|
|
|
|
it('warns on invalid JSON', () => {
|
|
const path = join(dir, 'config.json')
|
|
writeFileSync(path, '{ broken')
|
|
expect(readConfigFile(schema, path, opts)).toEqual([])
|
|
expect(errSpy).toHaveBeenCalledWith(
|
|
'testlabel: config file ' + path + ' is not valid JSON, ignoring'
|
|
)
|
|
})
|
|
|
|
it('warns when the top level is an array, not an object', () => {
|
|
const path = join(dir, 'config.json')
|
|
writeFileSync(path, JSON.stringify([conn]))
|
|
expect(readConfigFile(schema, path, opts)).toEqual([])
|
|
expect(errSpy).toHaveBeenCalledWith(
|
|
'testlabel: config file ' + path + ' must contain { "connections": [...] }, ignoring'
|
|
)
|
|
})
|
|
|
|
it('warns on null config', () => {
|
|
const path = join(dir, 'config.json')
|
|
writeFileSync(path, 'null')
|
|
expect(readConfigFile(schema, path, opts)).toEqual([])
|
|
expect(errSpy).toHaveBeenCalled()
|
|
})
|
|
|
|
it('warns on primitive config', () => {
|
|
const path = join(dir, 'config.json')
|
|
writeFileSync(path, '"just a string"')
|
|
expect(readConfigFile(schema, path, opts)).toEqual([])
|
|
expect(errSpy).toHaveBeenCalled()
|
|
})
|
|
|
|
it('warns when the connections key is missing or not an array', () => {
|
|
const path = join(dir, 'config.json')
|
|
writeFileSync(path, JSON.stringify({ connections: 'nope' }))
|
|
expect(readConfigFile(schema, path, opts)).toEqual([])
|
|
expect(errSpy).toHaveBeenCalledWith(
|
|
'testlabel: config file ' + path + ' must contain { "connections": [...] }, ignoring'
|
|
)
|
|
})
|
|
})
|