import-agent.test.js•7.49 kB
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { handleImportAgent, importAgentDefinition } from '../../../tools/agents/import-agent.js';
import fs from 'fs';
// Create mock instances
const mockFormDataInstance = {
    append: vi.fn(),
    getHeaders: vi.fn().mockReturnValue({ 'content-type': 'multipart/form-data; boundary=test' }),
};
const mockReadStream = {
    pipe: vi.fn(),
    on: vi.fn(),
};
// Mock dependencies
vi.mock('form-data', () => ({
    default: vi.fn(() => mockFormDataInstance),
}));
vi.mock('fs', () => ({
    default: {
        createReadStream: vi.fn(() => mockReadStream),
        existsSync: vi.fn(() => true),
    },
    createReadStream: vi.fn(() => mockReadStream),
    existsSync: vi.fn(() => true),
}));
describe('Import Agent Tool (LMP-94)', () => {
    let mockServer;
    beforeEach(() => {
        vi.clearAllMocks();
        // Reset mock behavior
        vi.mocked(fs.existsSync).mockReturnValue(true);
        vi.mocked(fs.createReadStream).mockReturnValue(mockReadStream);
        // Mock server
        mockServer = {
            api: {
                post: vi.fn(),
            },
            getApiHeaders: vi.fn().mockReturnValue({
                Authorization: 'Bearer test-password',
                'Content-Type': 'application/json',
            }),
            createErrorResponse: vi.fn((error) => {
                throw new Error(error);
            }),
        };
    });
    afterEach(() => {
        vi.clearAllMocks();
    });
    describe('Tool Definition', () => {
        it('should have correct tool name', () => {
            expect(importAgentDefinition.name).toBe('import_agent');
        });
        it('should have a description', () => {
            expect(importAgentDefinition.description).toBeDefined();
            expect(importAgentDefinition.description).toContain('Import');
        });
        it('should have input schema', () => {
            expect(importAgentDefinition.inputSchema).toBeDefined();
            expect(importAgentDefinition.inputSchema.type).toBe('object');
            expect(importAgentDefinition.inputSchema.properties).toHaveProperty('file_path');
        });
        it('should require file_path parameter', () => {
            expect(importAgentDefinition.inputSchema.required).toContain('file_path');
        });
    });
    describe('Import Agent Handler', () => {
        it('should successfully import an agent', async () => {
            const mockResponse = {
                data: {
                    id: 'agent-123',
                    name: 'Imported Agent',
                    model: 'gpt-4',
                    tools: ['tool1', 'tool2'],
                    created_at: '2024-01-01T00:00:00Z',
                },
            };
            mockServer.api.post.mockResolvedValueOnce(mockResponse);
            const result = await handleImportAgent(mockServer, {
                file_path: '/path/to/agent.json',
            });
            // Verify API call
            expect(mockServer.api.post).toHaveBeenCalledWith(
                '/agents/import',
                mockFormDataInstance,
                expect.objectContaining({
                    headers: expect.objectContaining({
                        Authorization: 'Bearer test-password',
                    }),
                    params: {},
                }),
            );
            // Verify FormData
            expect(mockFormDataInstance.append).toHaveBeenCalledWith(
                'file',
                mockReadStream,
                'agent.json',
            );
            // Verify result format
            expect(result).toHaveProperty('content');
            expect(result.content).toHaveLength(1);
            expect(result.content[0].type).toBe('text');
            // Parse the JSON response
            const responseData = JSON.parse(result.content[0].text);
            expect(responseData.agent_id).toBe('agent-123');
            expect(responseData.agent).toEqual(mockResponse.data);
        });
        it('should handle API errors', async () => {
            const mockError = new Error('Failed to import agent');
            mockError.response = {
                status: 400,
                data: { detail: 'Invalid agent file format' },
            };
            mockServer.api.post.mockRejectedValueOnce(mockError);
            await expect(
                handleImportAgent(mockServer, {
                    file_path: '/path/to/invalid.json',
                }),
            ).rejects.toThrow('Failed to import agent');
        });
        it('should handle missing file_path', async () => {
            await expect(handleImportAgent(mockServer, {})).rejects.toThrow(
                'Missing required argument: file_path',
            );
        });
        it('should handle non-existent file', async () => {
            vi.mocked(fs.existsSync).mockReturnValue(false);
            await expect(
                handleImportAgent(mockServer, {
                    file_path: '/nonexistent/agent.json',
                }),
            ).rejects.toThrow('File not found at path');
        });
        it('should handle optional parameters', async () => {
            const mockResponse = {
                data: { id: 'agent-123', name: 'Test Agent' },
            };
            mockServer.api.post.mockResolvedValueOnce(mockResponse);
            await handleImportAgent(mockServer, {
                file_path: '/path/to/agent.json',
                append_copy_suffix: false,
                override_existing_tools: true,
                project_id: 'project-456',
            });
            // Verify params were passed
            expect(mockServer.api.post).toHaveBeenCalledWith(
                '/agents/import',
                mockFormDataInstance,
                expect.objectContaining({
                    params: {
                        append_copy_suffix: false,
                        override_existing_tools: true,
                        project_id: 'project-456',
                    },
                }),
            );
        });
        it('should handle Windows-style paths', async () => {
            const mockResponse = {
                data: { id: 'agent-123', name: 'Test Agent' },
            };
            mockServer.api.post.mockResolvedValueOnce(mockResponse);
            await handleImportAgent(mockServer, {
                file_path: 'C:\\Users\\test\\agent.json',
            });
            // Verify filename extraction for Windows paths
            // The append call includes the full path on Windows
            const appendCalls = mockFormDataInstance.append.mock.calls;
            expect(appendCalls).toHaveLength(1);
            expect(appendCalls[0][0]).toBe('file');
            expect(appendCalls[0][1]).toBe(mockReadStream);
            // The filename might include the full path or just the basename
            expect(appendCalls[0][2]).toMatch(/agent\.json$/);
        });
        it('should handle network errors', async () => {
            const mockError = new Error('Network error');
            mockError.code = 'ECONNREFUSED';
            mockServer.api.post.mockRejectedValueOnce(mockError);
            await expect(
                handleImportAgent(mockServer, {
                    file_path: '/path/to/agent.json',
                }),
            ).rejects.toThrow('Failed to import agent');
        });
    });
});