import { describe, it, expect, beforeEach } from "vitest"; import { Test, TestingModule } from "@nestjs/testing"; import { ToolRegistryService } from "./tool-registry.service"; import type { McpTool } from "./interfaces"; describe("ToolRegistryService", () => { let service: ToolRegistryService; const mockTool1: McpTool = { name: "test_tool_1", description: "Test tool 1", inputSchema: { type: "object", properties: { param1: { type: "string" }, }, }, serverId: "server-1", }; const mockTool2: McpTool = { name: "test_tool_2", description: "Test tool 2", inputSchema: { type: "object", properties: { param2: { type: "number" }, }, }, serverId: "server-1", }; const mockTool3: McpTool = { name: "test_tool_3", description: "Test tool 3", inputSchema: { type: "object", properties: { param3: { type: "boolean" }, }, }, serverId: "server-2", }; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [ToolRegistryService], }).compile(); service = module.get(ToolRegistryService); }); describe("initialization", () => { it("should be defined", () => { expect(service).toBeDefined(); }); it("should start with empty registry", () => { const tools = service.listTools(); expect(tools).toHaveLength(0); }); }); describe("registerTool", () => { it("should register a new tool", () => { service.registerTool(mockTool1); const tool = service.getTool(mockTool1.name); expect(tool).toBeDefined(); expect(tool?.name).toBe(mockTool1.name); expect(tool?.description).toBe(mockTool1.description); }); it("should update existing tool on re-registration", () => { service.registerTool(mockTool1); const updatedTool: McpTool = { ...mockTool1, description: "Updated description", }; service.registerTool(updatedTool); const tool = service.getTool(mockTool1.name); expect(tool?.description).toBe("Updated description"); }); it("should register multiple tools", () => { service.registerTool(mockTool1); service.registerTool(mockTool2); service.registerTool(mockTool3); const tools = service.listTools(); expect(tools).toHaveLength(3); }); }); describe("unregisterTool", () => { it("should remove a registered tool", () => { service.registerTool(mockTool1); service.unregisterTool(mockTool1.name); const tool = service.getTool(mockTool1.name); expect(tool).toBeUndefined(); }); it("should not throw error when unregistering non-existent tool", () => { expect(() => service.unregisterTool("non-existent")).not.toThrow(); }); it("should only remove the specified tool", () => { service.registerTool(mockTool1); service.registerTool(mockTool2); service.unregisterTool(mockTool1.name); expect(service.getTool(mockTool1.name)).toBeUndefined(); expect(service.getTool(mockTool2.name)).toBeDefined(); }); }); describe("getTool", () => { it("should return tool by name", () => { service.registerTool(mockTool1); const tool = service.getTool(mockTool1.name); expect(tool).toEqual(mockTool1); }); it("should return undefined for non-existent tool", () => { const tool = service.getTool("non-existent"); expect(tool).toBeUndefined(); }); }); describe("listTools", () => { it("should return all registered tools", () => { service.registerTool(mockTool1); service.registerTool(mockTool2); service.registerTool(mockTool3); const tools = service.listTools(); expect(tools).toHaveLength(3); expect(tools).toContainEqual(mockTool1); expect(tools).toContainEqual(mockTool2); expect(tools).toContainEqual(mockTool3); }); it("should return empty array when no tools registered", () => { const tools = service.listTools(); expect(tools).toHaveLength(0); }); }); describe("listToolsByServer", () => { beforeEach(() => { service.registerTool(mockTool1); service.registerTool(mockTool2); service.registerTool(mockTool3); }); it("should return tools for specific server", () => { const server1Tools = service.listToolsByServer("server-1"); expect(server1Tools).toHaveLength(2); expect(server1Tools).toContainEqual(mockTool1); expect(server1Tools).toContainEqual(mockTool2); }); it("should return empty array for server with no tools", () => { const tools = service.listToolsByServer("non-existent-server"); expect(tools).toHaveLength(0); }); it("should not include tools from other servers", () => { const server2Tools = service.listToolsByServer("server-2"); expect(server2Tools).toHaveLength(1); expect(server2Tools).toContainEqual(mockTool3); expect(server2Tools).not.toContainEqual(mockTool1); }); }); describe("clearServerTools", () => { beforeEach(() => { service.registerTool(mockTool1); service.registerTool(mockTool2); service.registerTool(mockTool3); }); it("should remove all tools for a server", () => { service.clearServerTools("server-1"); const server1Tools = service.listToolsByServer("server-1"); expect(server1Tools).toHaveLength(0); }); it("should not affect tools from other servers", () => { service.clearServerTools("server-1"); const server2Tools = service.listToolsByServer("server-2"); expect(server2Tools).toHaveLength(1); }); it("should not throw error for non-existent server", () => { expect(() => service.clearServerTools("non-existent")).not.toThrow(); }); it("should allow re-registration after clearing", () => { service.clearServerTools("server-1"); service.registerTool(mockTool1); const tool = service.getTool(mockTool1.name); expect(tool).toBeDefined(); }); }); });