import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { mkdtemp, writeFile, rm, mkdir } from 'node:fs/promises'; import { join } from 'node:path'; import { tmpdir } from 'node:os'; import { loadProxyModels, getProxyModel } from '../src/proxymodel/loader.js'; describe('loadProxyModels', () => { let tempDir: string; beforeEach(async () => { tempDir = await mkdtemp(join(tmpdir(), 'proxymodel-test-')); }); afterEach(async () => { await rm(tempDir, { recursive: true, force: true }); }); it('loads built-in models when directory is empty', async () => { const models = await loadProxyModels(tempDir); expect(models.has('default')).toBe(true); expect(models.has('subindex')).toBe(true); expect(models.get('default')!.source).toBe('built-in'); }); it('loads built-in models when directory does not exist', async () => { const models = await loadProxyModels(join(tempDir, 'nonexistent')); expect(models.has('default')).toBe(true); expect(models.has('subindex')).toBe(true); }); it('loads local YAML files', async () => { const yaml = `kind: ProxyModel metadata: name: custom spec: stages: - type: passthrough `; await writeFile(join(tempDir, 'custom.yaml'), yaml); const models = await loadProxyModels(tempDir); expect(models.has('custom')).toBe(true); expect(models.get('custom')!.source).toBe('local'); expect(models.get('custom')!.spec.stages[0]!.type).toBe('passthrough'); }); it('loads .yml files too', async () => { const yaml = `metadata: name: alt spec: stages: - type: paginate config: pageSize: 4000 `; await writeFile(join(tempDir, 'alt.yml'), yaml); const models = await loadProxyModels(tempDir); expect(models.has('alt')).toBe(true); expect(models.get('alt')!.spec.stages[0]!.config).toEqual({ pageSize: 4000 }); }); it('local models override built-ins with same name', async () => { const yaml = `kind: ProxyModel metadata: name: default spec: controller: none stages: - type: passthrough cacheable: false `; await writeFile(join(tempDir, 'default.yaml'), yaml); const models = await loadProxyModels(tempDir); expect(models.get('default')!.source).toBe('local'); expect(models.get('default')!.spec.controller).toBe('none'); }); it('skips invalid YAML files without breaking', async () => { await writeFile(join(tempDir, 'valid.yaml'), `metadata:\n name: good\nspec:\n stages:\n - type: passthrough\n`); await writeFile(join(tempDir, 'invalid.yaml'), `metadata:\n name: \nspec:\n stages: []\n`); const models = await loadProxyModels(tempDir); expect(models.has('good')).toBe(true); expect(models.has('')).toBe(false); }); it('ignores non-yaml files', async () => { await writeFile(join(tempDir, 'readme.md'), '# Readme'); await writeFile(join(tempDir, 'notes.txt'), 'Notes'); const models = await loadProxyModels(tempDir); // Only built-ins expect(models.size).toBe(2); }); }); describe('getProxyModel', () => { let tempDir: string; beforeEach(async () => { tempDir = await mkdtemp(join(tmpdir(), 'proxymodel-test-')); }); afterEach(async () => { await rm(tempDir, { recursive: true, force: true }); }); it('returns requested model by name', async () => { const model = await getProxyModel('subindex', tempDir); expect(model.metadata.name).toBe('subindex'); }); it('falls back to default for unknown model', async () => { const model = await getProxyModel('nonexistent', tempDir); expect(model.metadata.name).toBe('default'); }); });