import { describe, it, expect, beforeAll, vi } from 'vitest'; describe('AI API Service Tests', () => { beforeAll(() => { process.env.API_KEYS = 'test-key-1,test-key-2'; process.env.ADMIN_API_KEYS = 'admin-key-1'; process.env.OPENAI_API_KEY = 'sk-test-mock-key'; }); describe('Authentication', () => { it('should validate correct API key', () => { const { validateApiKey } = require('../backend/utils/auth'); const result = validateApiKey('Bearer test-key-1'); expect(result.apiKey).toBe('test-key-1'); expect(result.tier).toBe('default'); }); it('should validate admin API key', () => { const { validateApiKey } = require('../backend/utils/auth'); const result = validateApiKey('Bearer admin-key-1'); expect(result.apiKey).toBe('admin-key-1'); expect(result.tier).toBe('admin'); }); it('should reject invalid API key', () => { const { validateApiKey } = require('../backend/utils/auth'); expect(() => validateApiKey('Bearer invalid-key')).toThrow('Invalid API key'); }); it('should reject missing API key', () => { const { validateApiKey } = require('../backend/utils/auth'); expect(() => validateApiKey('')).toThrow('Missing Authorization header'); }); }); describe('Rate Limiting', () => { it('should allow requests within rate limit', () => { const { rateLimiter } = require('../backend/utils/rate_limit'); const info = rateLimiter.checkRateLimit('test-key-1', 'default'); expect(info.remaining).toBeGreaterThanOrEqual(0); expect(info.limit).toBeGreaterThan(0); }); it('should have higher limit for admin tier', () => { const { rateLimiter } = require('../backend/utils/rate_limit'); const defaultInfo = rateLimiter.getRateLimitInfo('test-key-1', 'default'); const adminInfo = rateLimiter.getRateLimitInfo('admin-key-1', 'admin'); expect(adminInfo.limit).toBeGreaterThan(defaultInfo.limit); }); }); describe('Vector DB', () => { it('should store and retrieve vectors from in-memory DB', async () => { const { InMemoryVectorDB } = require('../backend/adapters/vector_db_adapter'); const db = new InMemoryVectorDB(); await db.upsert([ { id: 'test-1', values: [1, 0, 0], metadata: { content: 'Test document 1' }, }, { id: 'test-2', values: [0, 1, 0], metadata: { content: 'Test document 2' }, }, ]); const results = await db.query([1, 0, 0], 2); expect(results.length).toBe(2); expect(results[0].id).toBe('test-1'); expect(results[0].score).toBeGreaterThan(results[1].score); }); it('should filter results based on metadata', async () => { const { InMemoryVectorDB } = require('../backend/adapters/vector_db_adapter'); const db = new InMemoryVectorDB(); await db.upsert([ { id: 'doc-1', values: [1, 0, 0], metadata: { category: 'tech', content: 'Tech document' }, }, { id: 'doc-2', values: [0.9, 0, 0], metadata: { category: 'science', content: 'Science document' }, }, ]); const results = await db.query([1, 0, 0], 5, { category: 'tech' }); expect(results.length).toBe(1); expect(results[0].id).toBe('doc-1'); }); it('should delete vectors', async () => { const { InMemoryVectorDB } = require('../backend/adapters/vector_db_adapter'); const db = new InMemoryVectorDB(); await db.upsert([ { id: 'delete-1', values: [1, 0, 0], metadata: {} }, ]); let results = await db.query([1, 0, 0], 5); expect(results.length).toBe(1); await db.delete(['delete-1']); results = await db.query([1, 0, 0], 5); expect(results.length).toBe(0); }); }); describe('Document Service', () => { it('should chunk text correctly', () => { const { documentService } = require('../backend/services/document_service'); const text = 'a'.repeat(2500); const chunks = documentService['chunkText'](text, 'doc-1', {}); expect(chunks.length).toBeGreaterThan(1); expect(chunks[0].chunk_index).toBe(0); expect(chunks[0].doc_id).toBe('doc-1'); }); it('should extract text from txt file', async () => { const { documentService } = require('../backend/services/document_service'); const content = Buffer.from('This is a test document', 'utf-8'); const text = await documentService['extractText']('test.txt', content); expect(text).toBe('This is a test document'); }); }); describe('Metrics', () => { it('should track requests', () => { const { metrics } = require('../backend/utils/metrics'); const initialMetrics = metrics.getMetrics(); metrics.incrementRequests('/test'); const updatedMetrics = metrics.getMetrics(); expect(updatedMetrics.requests_total).toBeGreaterThan(initialMetrics.requests_total); }); it('should track errors', () => { const { metrics } = require('../backend/utils/metrics'); const initialMetrics = metrics.getMetrics(); metrics.incrementErrors(); const updatedMetrics = metrics.getMetrics(); expect(updatedMetrics.errors_total).toBeGreaterThan(initialMetrics.errors_total); }); it('should track response times', () => { const { metrics } = require('../backend/utils/metrics'); metrics.recordResponseTime(100); metrics.recordResponseTime(200); const metricsData = metrics.getMetrics(); expect(metricsData.average_response_time_ms).toBeGreaterThan(0); }); }); describe('Logger', () => { it('should log messages at appropriate levels', () => { const { logger } = require('../backend/utils/logger'); const consoleSpy = vi.spyOn(console, 'log'); logger.info('Test message'); expect(consoleSpy).toHaveBeenCalled(); consoleSpy.mockRestore(); }); }); describe('Configuration', () => { it('should load default configuration', () => { const { loadConfig } = require('../backend/types/config'); const config = loadConfig(); expect(config.auth.apiKeys).toContain('test-key-1'); expect(config.rateLimit.default).toBeGreaterThan(0); expect(config.documents.maxFileSizeMB).toBeGreaterThan(0); }); it('should parse comma-separated API keys', () => { const { loadConfig } = require('../backend/types/config'); const config = loadConfig(); expect(Array.isArray(config.auth.apiKeys)).toBe(true); expect(config.auth.apiKeys.length).toBeGreaterThan(0); }); }); describe('AI Service', () => { it('should initialize with available adapters', () => { const { aiService } = require('../backend/services/ai_service'); const models = aiService.getAvailableModels(); expect(Array.isArray(models)).toBe(true); }); }); describe('RAG Service', () => { it('should build RAG prompt correctly', () => { const { ragService } = require('../backend/services/rag_service'); const prompt = ragService['buildRAGPrompt']( 'What is AI?', 'AI stands for Artificial Intelligence' ); expect(prompt).toContain('What is AI?'); expect(prompt).toContain('AI stands for Artificial Intelligence'); }); }); describe('Ingestion Worker', () => { it('should track job status', async () => { const { ingestionWorker } = require('../backend/workers/ingestion_worker'); await ingestionWorker.addJob('job-1', 'test.pdf'); const job = ingestionWorker.getJobStatus('job-1'); expect(job).toBeDefined(); expect(job?.doc_id).toBe('job-1'); expect(job?.status).toBe('pending'); }); }); });