Files
promptfoo--promptfoo/test/providers/azure/chat-mcp-integration.test.ts
T
wehub-resource-sync 0d3cb498a3
CI / Shell Format Check (push) Has been cancelled
CI / Check Ruby (3.4) (push) Has been cancelled
CI / CI Config (push) Has been cancelled
CI / Test on Node ${{ matrix.node }} and ${{ matrix.os }}${{ matrix.shard && format(' (shard {0}/3)', matrix.shard) || '' }} (push) Has been cancelled
CI / Build on Node ${{ matrix.node }} (push) Has been cancelled
CI / Style Check (push) Has been cancelled
CI / Generate Assets (push) Has been cancelled
CI / Check Python (3.14) (push) Has been cancelled
CI / Check Python (3.9) (push) Has been cancelled
CI / Build Docs (push) Has been cancelled
CI / Code Scan Action (push) Has been cancelled
CI / Site tests (push) Has been cancelled
CI / webui tests (push) Has been cancelled
CI / Run Integration Tests (push) Has been cancelled
CI / Run Smoke Tests (push) Has been cancelled
CI / Go Tests (push) Has been cancelled
CI / Share Test (push) Has been cancelled
CI / Redteam (Production API) (push) Has been cancelled
CI / Redteam (Staging API) (push) Has been cancelled
CI / GitHub Actions Lint (push) Has been cancelled
CI / Check Ruby (3.0) (push) Has been cancelled
release-please / release-please (push) Has been cancelled
release-please / build (push) Has been cancelled
release-please / publish-npm (push) Has been cancelled
release-please / publish-npm-backfill (push) Has been cancelled
release-please / docker (push) Has been cancelled
release-please / publish-code-scan-action (push) Has been cancelled
release-please / attest-code-scan-action (push) Has been cancelled
Deploy local.promptfoo.app / Deploy to Cloudflare Pages (push) Has been cancelled
Test and Publish Multi-arch Docker Image / test (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-amd64 platform:linux/amd64 runner:ubuntu-latest]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-arm64 platform:linux/arm64 runner:ubuntu-24.04-arm]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / merge-docker-digests (push) Has been cancelled
Test and Publish Multi-arch Docker Image / Attest Multi-arch Image (push) Has been cancelled
Validate Renovate Config / Validate Renovate Configuration (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:24:08 +08:00

194 lines
5.9 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { AzureChatCompletionProvider } from '../../../src/providers/azure/chat';
const mcpMocks = vi.hoisted(() => {
const mockInitialize = vi.fn().mockResolvedValue(undefined);
const mockCleanup = vi.fn().mockResolvedValue(undefined);
const mockGetAllTools = vi.fn().mockReturnValue([
{
name: 'list_resources',
description: 'List available token system resources',
inputSchema: { type: 'object' },
},
]);
const mockCallTool = vi.fn().mockResolvedValue({
content: 'Available resources: [button-tokens.json, color-tokens.json, spacing-tokens.json]',
});
class MockMCPClient {
initialize = mockInitialize;
cleanup = mockCleanup;
getAllTools = mockGetAllTools;
callTool = mockCallTool;
}
return {
MockMCPClient,
mockInitialize,
mockCleanup,
mockGetAllTools,
mockCallTool,
};
});
// Mock external dependencies
vi.mock('../../../src/cache');
vi.mock('../../../src/logger');
vi.mock('../../../src/providers/mcp/client', async (importOriginal) => {
return {
...(await importOriginal()),
MCPClient: mcpMocks.MockMCPClient,
};
});
describe('AzureChatCompletionProvider MCP Integration', () => {
let provider: AzureChatCompletionProvider;
beforeEach(() => {
// Reset mocks
mcpMocks.mockInitialize.mockReset().mockResolvedValue(undefined);
mcpMocks.mockCleanup.mockReset().mockResolvedValue(undefined);
mcpMocks.mockGetAllTools.mockReset().mockReturnValue([
{
name: 'list_resources',
description: 'List available token system resources',
inputSchema: { type: 'object' },
},
]);
mcpMocks.mockCallTool.mockReset().mockResolvedValue({
content: 'Available resources: [button-tokens.json, color-tokens.json, spacing-tokens.json]',
});
// Create provider with MCP enabled
provider = new AzureChatCompletionProvider('test-deployment', {
config: {
apiKey: 'test-key',
apiHost: 'https://test.openai.azure.com',
mcp: {
enabled: true,
server: {
command: 'npx',
args: ['@fluentui-contrib/token-analyzer-mcp'],
name: 'test-token-mcp',
},
},
},
});
});
afterEach(async () => {
await provider.cleanup();
vi.clearAllMocks();
});
it('should integrate MCP tools with FunctionCallbackHandler', async () => {
// Wait for MCP initialization
await (provider as any).initializationPromise;
// Verify MCP client was initialized
expect(mcpMocks.mockInitialize).toHaveBeenCalled();
// Test that the function callback handler now has the MCP client
const handler = (provider as any).functionCallbackHandler;
expect(handler).toBeDefined();
expect((handler as any).mcpClient).toBeDefined();
});
it('should execute MCP tool through FunctionCallbackHandler', async () => {
// Wait for MCP initialization
await (provider as any).initializationPromise;
const handler = (provider as any).functionCallbackHandler;
// Simulate a tool call that matches an MCP tool
const toolCall = {
name: 'list_resources',
arguments: '{}',
};
const result = await handler.processCall(toolCall, {});
// Verify MCP tool was called
expect(mcpMocks.mockCallTool).toHaveBeenCalledWith('list_resources', {});
// Verify result format matches expected pattern (not [object Object])
expect(result).toEqual({
output:
'MCP Tool Result (list_resources): Available resources: [button-tokens.json, color-tokens.json, spacing-tokens.json]',
isError: false,
});
// Ensure it's not the problematic [object Object] output
expect(result.output).not.toContain('[object Object]');
});
it('should handle MCP tool errors gracefully', async () => {
// Wait for MCP initialization
await (provider as any).initializationPromise;
// Configure mock to return an error
mcpMocks.mockCallTool.mockResolvedValue({
content: '',
error: 'MCP server connection failed',
});
const handler = (provider as any).functionCallbackHandler;
const toolCall = {
name: 'list_resources',
arguments: '{}',
};
const result = await handler.processCall(toolCall, {});
expect(result).toEqual({
output: 'MCP Tool Error (list_resources): MCP server connection failed',
isError: true,
});
});
it('should work without MCP enabled (backwards compatibility)', () => {
// Create provider without MCP
const providerWithoutMCP = new AzureChatCompletionProvider('test-deployment', {
config: {
apiKey: 'test-key',
apiHost: 'https://test.openai.azure.com',
// No MCP config
},
});
// Should not have MCP client
expect((providerWithoutMCP as any).mcpClient).toBeNull();
// FunctionCallbackHandler should work without MCP client
const handler = (providerWithoutMCP as any).functionCallbackHandler;
expect(handler).toBeDefined();
expect((handler as any).mcpClient).toBeUndefined();
});
it('should prioritize MCP tools over function callbacks', async () => {
// Wait for MCP initialization
await (provider as any).initializationPromise;
const handler = (provider as any).functionCallbackHandler;
// Create a function callback with the same name as an MCP tool
const functionCallbacks = {
list_resources: vi.fn().mockResolvedValue('Function callback result'),
};
const toolCall = {
name: 'list_resources',
arguments: '{}',
};
const result = await handler.processCall(toolCall, functionCallbacks);
// Should call MCP tool, not function callback
expect(mcpMocks.mockCallTool).toHaveBeenCalledWith('list_resources', {});
expect(functionCallbacks.list_resources).not.toHaveBeenCalled();
// Result should be from MCP tool
expect(result.output).toContain('MCP Tool Result');
});
});