UNPKG

mcp-smart

Version:

MCP server providing multi-advisor AI consultations via OpenRouter API with advanced caching, rate limiting, and security features

170 lines 6.96 kB
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest'; import axios from 'axios'; import { SmartAdvisorServer } from '../SmartAdvisorServer.js'; vi.mock('axios', async (importOriginal) => { const actual = await importOriginal(); return { ...actual, default: { post: vi.fn(), AxiosError: actual.AxiosError }, AxiosError: actual.AxiosError }; }); const mockedAxios = vi.mocked(axios); describe('Integration Tests', () => { let server; const originalApiKey = process.env.OPENROUTER_API_KEY; beforeAll(() => { if (!process.env.OPENROUTER_API_KEY) { process.env.OPENROUTER_API_KEY = 'test-key-for-integration'; } // Increase rate limits for testing process.env.RATE_LIMIT_REQUESTS = '100'; process.env.RATE_LIMIT_WINDOW = '60000'; // Disable caching for tests to avoid interference process.env.CACHE_TTL = '0'; vi.clearAllMocks(); server = new SmartAdvisorServer(); }); afterAll(() => { process.env.OPENROUTER_API_KEY = originalApiKey; }); describe('End-to-End Tool Flow', () => { it('should handle complete tool workflow', async () => { const tools = await server.listTools(); expect(tools.tools).toHaveLength(7); expect(tools.tools[0].name).toBe('smart_advisor'); const toolSchema = tools.tools[0].inputSchema; expect(toolSchema.properties.model.enum).toContain('google'); expect(toolSchema.properties.model.enum).toContain('openai'); expect(toolSchema.properties.model.enum).toContain('deepseek'); expect(toolSchema.properties.model.enum).toContain('random'); expect(toolSchema.properties.model.enum).toContain('all'); expect(toolSchema.required).toEqual(['model', 'task']); }); it('should validate required parameters', async () => { await expect(server.callTool('smart_advisor', { model: 'google' })).rejects.toThrow(); await expect(server.callTool('smart_advisor', { task: 'test task' })).rejects.toThrow(); }); it('should handle all supported models', async () => { const mockResponse = { data: { choices: [{ message: { content: 'Mock response for integration test' } }] } }; const models = ['google', 'openai', 'deepseek']; for (const model of models) { mockedAxios.post.mockResolvedValueOnce(mockResponse); const result = await server.callTool('smart_advisor', { model, task: 'Simple test task' }); expect(result.content[0].text).toBe('Mock response for integration test'); } }); it('should handle random model selection', async () => { const mockResponse = { data: { choices: [{ message: { content: 'Random provider response' } }] } }; // Test random multiple times to ensure it's working const results = []; for (let i = 0; i < 5; i++) { mockedAxios.post.mockResolvedValueOnce(mockResponse); const result = await server.callTool('smart_advisor', { model: 'random', task: 'Test random provider selection' }); expect(result.content[0].text).toBe('Random provider response'); results.push(result); } // Verify all calls succeeded expect(results).toHaveLength(5); }); }); describe('Error Handling', () => { it('should handle network timeouts gracefully', async () => { vi.clearAllMocks(); mockedAxios.post.mockRejectedValueOnce(new Error('Network timeout')); await expect(server.callTool('smart_advisor', { model: 'google', task: 'Unique-timeout-test-' + Math.random() })).rejects.toThrow('Failed after'); }); it('should preserve error context', async () => { try { await server.callTool('smart_advisor', { model: 'invalid-model', task: 'test' }); } catch (error) { expect(error).toBeInstanceOf(Error); expect(error.message).toContain('Unknown routing strategy'); } }); }); describe('Input Validation', () => { it('should handle edge cases in task input', async () => { vi.clearAllMocks(); const mockResponse = { data: { choices: [{ message: { content: 'Edge case response' } }] } }; const edgeCases = [ { task: 'edge-case-unique-1-' + Math.random(), expectError: false }, { task: 'edge-case-unique-2-' + Math.random() + 'a'.repeat(50), expectError: false }, { task: 'edge-case-unique-3-' + Math.random() + '-special: @#$%^&*()', expectError: false } ]; for (const testCase of edgeCases) { mockedAxios.post.mockResolvedValueOnce(mockResponse); const result = await server.callTool('smart_advisor', { model: 'google', task: testCase.task }); expect(result.content[0].text).toBe('Edge case response'); } }); it('should handle optional context parameter', async () => { vi.clearAllMocks(); const mockResponse = { data: { choices: [{ message: { content: 'Context test response' } }] } }; // Test just one case to avoid rate limits mockedAxios.post.mockResolvedValueOnce(mockResponse); const result = await server.callTool('smart_advisor', { model: 'deepseek', task: 'Context-test-unique-task-' + Math.random(), context: 'Simple context' }); expect(result.content[0].text).toBe('Context test response'); }); }); }); //# sourceMappingURL=integration.test.js.map