openreader/tests/unit/admin-providers-validation.vitest.spec.ts

138 lines
4 KiB
TypeScript

import { describe, expect, test } from 'vitest';
import { inArray } from 'drizzle-orm';
import { db } from '../../src/db';
import { adminProviders } from '../../src/db/schema';
import {
AdminProviderError,
listAdminProviders,
toMasked,
validateProviderType,
validateSlug,
type AdminProviderRecord,
} from '../../src/lib/server/admin/providers';
describe('admin provider validation', () => {
test('normalizes valid slugs to lowercase', () => {
expect(validateSlug('My-Provider-1')).toBe('my-provider-1');
});
test('rejects built-in provider ids as slugs', () => {
expect(() => validateSlug('openai')).toThrow(AdminProviderError);
expect(() => validateSlug('custom-openai')).toThrow('reserved');
});
test('rejects malformed slug values', () => {
expect(() => validateSlug('-bad-')).toThrow(AdminProviderError);
expect(() => validateSlug('bad_slug')).toThrow(AdminProviderError);
expect(() => validateSlug('')).toThrow(AdminProviderError);
});
test('accepts only known provider types', () => {
expect(validateProviderType('openai')).toBe('openai');
expect(() => validateProviderType('unknown')).toThrow(AdminProviderError);
});
test('masks api key from last4 in list responses', () => {
const record: AdminProviderRecord = {
id: 'id-1',
slug: 'shared-one',
displayName: 'Shared One',
providerType: 'openai',
baseUrl: null,
apiKeyCiphertext: 'ciphertext',
apiKeyIv: 'iv',
apiKeyLast4: 'abcd',
defaultModel: 'gpt-4o-mini-tts',
defaultInstructions: 'warm tone',
enabled: true,
createdAt: 1,
updatedAt: 1,
};
expect(toMasked(record).apiKeyMask).toBe('••••abcd');
});
test('lists providers in deterministic updated/created/slug order', async () => {
const suffix = `${Date.now()}${Math.random().toString(36).slice(2, 8)}`;
const inserted = [
{
id: `prov-aaa-${suffix}`,
slug: `ord-aaa-${suffix}`,
displayName: 'Order AAA',
providerType: 'openai' as const,
baseUrl: null,
apiKeyCiphertext: 'cipher',
apiKeyIv: 'iv',
apiKeyLast4: '1111',
defaultModel: null,
defaultInstructions: null,
enabled: 1,
createdAt: 200,
updatedAt: 300,
},
{
id: `prov-zzz-${suffix}`,
slug: `ord-zzz-${suffix}`,
displayName: 'Order ZZZ',
providerType: 'openai' as const,
baseUrl: null,
apiKeyCiphertext: 'cipher',
apiKeyIv: 'iv',
apiKeyLast4: '2222',
defaultModel: null,
defaultInstructions: null,
enabled: 1,
createdAt: 200,
updatedAt: 300,
},
{
id: `prov-mid-${suffix}`,
slug: `ord-mid-${suffix}`,
displayName: 'Order MID',
providerType: 'openai' as const,
baseUrl: null,
apiKeyCiphertext: 'cipher',
apiKeyIv: 'iv',
apiKeyLast4: '3333',
defaultModel: null,
defaultInstructions: null,
enabled: 1,
createdAt: 150,
updatedAt: 300,
},
{
id: `prov-old-${suffix}`,
slug: `ord-old-${suffix}`,
displayName: 'Order OLD',
providerType: 'openai' as const,
baseUrl: null,
apiKeyCiphertext: 'cipher',
apiKeyIv: 'iv',
apiKeyLast4: '4444',
defaultModel: null,
defaultInstructions: null,
enabled: 1,
createdAt: 999,
updatedAt: 200,
},
];
try {
await db.insert(adminProviders).values(inserted);
const listed = await listAdminProviders();
const ordered = listed
.filter((row) => row.slug.endsWith(suffix))
.map((row) => row.slug);
expect(ordered).toEqual([
`ord-aaa-${suffix}`,
`ord-zzz-${suffix}`,
`ord-mid-${suffix}`,
`ord-old-${suffix}`,
]);
} finally {
await db.delete(adminProviders).where(inArray(adminProviders.id, inserted.map((row) => row.id)));
}
});
});