Skip to main content
Glama
bulk-surface-coverage.test.ts6.13 kB
jest.mock('@/config', () => ({ getTeamCityUrl: () => 'https://example.test', getTeamCityToken: () => 'token', getMCPMode: () => 'full', })); describe('tools: bulk surface coverage for list & queue ops', () => { afterEach(() => { jest.resetModules(); jest.clearAllMocks(); }); it('list tools accept fields/locator and queue ops execute', async () => { await new Promise<void>((resolve, reject) => { jest.isolateModules(() => { (async () => { const projects = { getAllProjects: jest.fn(async () => ({ data: { project: [], count: 0 } })), }; const buildTypes = { getAllBuildTypes: jest.fn(async () => ({ data: { buildType: [], count: 0 } })), }; const builds = { getAllBuilds: jest.fn(async () => ({ data: { build: [], count: 0 } })) }; const agents = { getAllAgents: jest.fn(async () => ({ data: { agent: [], count: 0 } })), setEnabledInfo: jest.fn(async () => ({ data: {} })), } as unknown as { getAllAgents: jest.Mock; setEnabledInfo: jest.Mock; }; const agentPools = { getAllAgentPools: jest.fn(async () => ({ data: { agentPool: [], count: 0 } })), }; const vcsRoots = { getAllVcsRoots: jest.fn(async () => ({ data: { 'vcs-root': [], count: 0 } })), }; const buildQueue = { getAllQueuedBuilds: jest.fn(async () => ({ data: { build: [], count: 0 } })), setQueuedBuildsOrder: jest.fn(async () => ({ data: {} })), deleteQueuedBuild: jest.fn(async () => ({ data: {} })), }; jest.doMock('@/api-client', () => ({ TeamCityAPI: { getInstance: () => ({ projects, buildTypes, builds, agents, agentPools, vcsRoots, buildQueue, }), }, })); // eslint-disable-next-line @typescript-eslint/no-var-requires const { getTool } = require('@/tools'); // Exercise list tools with fields/locator await getTool('list_projects').handler({ locator: 'archived:false', pageSize: 1, fields: '$short', }); await getTool('list_build_configs').handler({ locator: 'paused:false', pageSize: 1, fields: 'id,name', }); await getTool('list_builds').handler({ locator: 'state:running', pageSize: 1, fields: 'id,state', }); await getTool('list_agents').handler({ locator: 'enabled:true', pageSize: 1, fields: 'id,name', }); await getTool('list_agent_pools').handler({ pageSize: 1, fields: 'id,name' }); await getTool('list_vcs_roots').handler({ pageSize: 1, fields: 'id,name' }); await getTool('list_queued_builds').handler({ locator: 'project:(id:Root)', pageSize: 1, fields: 'id,waitReason', }); // Exercise set_build_configs_paused with cancelQueued await getTool('set_build_configs_paused').handler({ buildTypeIds: ['bt1', 'bt2'], paused: true, cancelQueued: true, }); // Exercise pause/resume queue by pool // Supply one agent to disable/enable to touch those branches agents.getAllAgents.mockResolvedValueOnce({ data: { agent: [{ id: '123' }], count: 1 }, } as unknown as { data: { agent: Array<{ id: string }>; count: number } }); await getTool('pause_queue_for_pool').handler({ poolId: '1', comment: 'maint', until: '2025-01-01T00:00:00Z', }); agents.getAllAgents.mockResolvedValueOnce({ data: { agent: [{ id: '123' }], count: 1 }, } as unknown as { data: { agent: Array<{ id: string }>; count: number } }); await getTool('resume_queue_for_pool').handler({ poolId: '1' }); // Behavior: no exceptions and handlers returned successfully resolve(); })().catch(reject); }); }); }); it('set_build_configs_paused skips queued builds with null id', async () => { await new Promise<void>((resolve, reject) => { jest.isolateModules(() => { (async () => { const buildTypes = { setBuildTypeField: jest.fn(async () => ({})), }; const buildQueue = { getAllQueuedBuilds: jest.fn(async () => ({ data: { build: [ { id: 1001, buildTypeId: 'bt1' }, { buildTypeId: 'bt2' }, // No id - should be skipped { id: null, buildTypeId: 'bt1' }, // Null id - should be skipped ], }, })), deleteQueuedBuild: jest.fn(async () => ({})), }; jest.doMock('@/api-client', () => ({ TeamCityAPI: { getInstance: () => ({ buildTypes, buildQueue, }), }, })); // eslint-disable-next-line @typescript-eslint/no-var-requires const { getTool } = require('@/tools'); const res = await getTool('set_build_configs_paused').handler({ buildTypeIds: ['bt1', 'bt2'], paused: true, cancelQueued: true, }); const payload = JSON.parse((res.content?.[0]?.text as string) ?? '{}'); expect(payload.success).toBe(true); expect(payload.updated).toBe(2); // Both bt1 and bt2 paused expect(payload.canceled).toBe(1); // Only the build with id 1001 was canceled expect(buildQueue.deleteQueuedBuild).toHaveBeenCalledTimes(1); expect(buildQueue.deleteQueuedBuild).toHaveBeenCalledWith('1001'); resolve(); })().catch(reject); }); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Daghis/teamcity-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server