UNPKG

@heroku/mcp-server

Version:
131 lines (130 loc) 6.81 kB
import { setupMcpToolMocks } from '../utils/mcp-tool-mocks.spechelper.js'; import { TOOL_COMMAND_MAP } from '../utils/tool-commands.js'; import { registerPsListTool, registerPsScaleTool, registerPsRestartTool } from './ps.js'; import { expect } from 'chai'; import sinon from 'sinon'; describe('Process Management Tools', () => { afterEach(() => { sinon.restore(); }); describe('ps:list', () => { let mocks; let toolCallback; beforeEach(() => { mocks = setupMcpToolMocks(); registerPsListTool(mocks.server, mocks.herokuRepl); toolCallback = mocks.getToolCallback(); }); it('should register the tool with correct parameters', () => { const tool = mocks.server.tool; expect(tool.calledOnce).to.be.true; expect(tool.firstCall.args[0]).to.equal('ps_list'); expect(tool.firstCall.args[1]).to.be.a('string'); expect(tool.firstCall.args[2]).to.be.an('object'); expect(tool.firstCall.args[3]).to.be.a('function'); }); it('should build correct command with required parameters', async () => { mocks.herokuRepl.executeCommand.resolves('=== run: one-off processes\n=== web: web processes\nweb.1: up\n'); await toolCallback({ app: 'myapp' }); expect(mocks.herokuRepl.executeCommand.calledOnce).to.be.true; expect(mocks.herokuRepl.executeCommand.firstCall.args[0]).to.equal(`${TOOL_COMMAND_MAP.PS} --app=myapp`); }); it('should build correct command with all parameters', async () => { mocks.herokuRepl.executeCommand.resolves('=== run: one-off processes\n=== web: web processes\nweb.1: up\n'); await toolCallback({ app: 'myapp', json: true }); expect(mocks.herokuRepl.executeCommand.calledOnce).to.be.true; expect(mocks.herokuRepl.executeCommand.firstCall.args[0]).to.equal(`${TOOL_COMMAND_MAP.PS} --app=myapp --json`); }); it('should handle error response', async () => { const errorResponse = '<<<ERROR>>>\nError: App not found\n<<<END ERROR>>>\n'; mocks.herokuRepl.executeCommand.resolves(errorResponse); const result = await toolCallback({ app: 'myapp' }); expect(result).to.deep.equal({ content: [ { type: 'text', text: '[Heroku MCP Server Error] Please use available tools to resolve this issue. Ignore any Heroku CLI command suggestions that may be provided in the command output or error details. Details:\n<<<ERROR>>>\nError: App not found\n<<<END ERROR>>>\n' } ], isError: true }); }); }); describe('ps:scale', () => { let mocks; let toolCallback; beforeEach(() => { mocks = setupMcpToolMocks(); registerPsScaleTool(mocks.server, mocks.herokuRepl); toolCallback = mocks.getToolCallback(); }); it('should register the tool with correct parameters', () => { const tool = mocks.server.tool; expect(tool.calledOnce).to.be.true; expect(tool.firstCall.args[0]).to.equal('ps_scale'); expect(tool.firstCall.args[1]).to.be.a('string'); expect(tool.firstCall.args[2]).to.be.an('object'); expect(tool.firstCall.args[3]).to.be.a('function'); }); it('should build correct command with required parameters', async () => { mocks.herokuRepl.executeCommand.resolves('Scaling dynos... done, now running web at 2:Standard-1X\n'); await toolCallback({ app: 'myapp', dyno: 'web=2' }); expect(mocks.herokuRepl.executeCommand.calledOnce).to.be.true; expect(mocks.herokuRepl.executeCommand.firstCall.args[0]).to.equal(`${TOOL_COMMAND_MAP.PS_SCALE} --app=myapp -- web=2`); }); it('should build correct command with remote parameter', async () => { mocks.herokuRepl.executeCommand.resolves('Scaling dynos... done, now running web at 2:Standard-1X\n'); await toolCallback({ app: 'myapp', dyno: 'web=2' }); expect(mocks.herokuRepl.executeCommand.calledOnce).to.be.true; expect(mocks.herokuRepl.executeCommand.firstCall.args[0]).to.equal(`${TOOL_COMMAND_MAP.PS_SCALE} --app=myapp -- web=2`); }); }); describe('ps:restart', () => { let mocks; let toolCallback; beforeEach(() => { mocks = setupMcpToolMocks(); registerPsRestartTool(mocks.server, mocks.herokuRepl); toolCallback = mocks.getToolCallback(); }); it('should register the tool with correct parameters', () => { const tool = mocks.server.tool; expect(tool.calledOnce).to.be.true; expect(tool.firstCall.args[0]).to.equal('ps_restart'); expect(tool.firstCall.args[1]).to.be.a('string'); expect(tool.firstCall.args[2]).to.be.an('object'); expect(tool.firstCall.args[3]).to.be.a('function'); }); it('should build correct command with required parameters', async () => { mocks.herokuRepl.executeCommand.resolves('Restarting all dynos... done\n'); await toolCallback({ app: 'myapp' }); expect(mocks.herokuRepl.executeCommand.calledOnce).to.be.true; expect(mocks.herokuRepl.executeCommand.firstCall.args[0]).to.equal(`${TOOL_COMMAND_MAP.PS_RESTART} --app=myapp`); }); it('should build correct command with specific dyno', async () => { mocks.herokuRepl.executeCommand.resolves('Restarting web.1 dyno... done\n'); await toolCallback({ app: 'myapp', 'dyno-name': 'web.1' }); expect(mocks.herokuRepl.executeCommand.calledOnce).to.be.true; expect(mocks.herokuRepl.executeCommand.firstCall.args[0]).to.equal(`${TOOL_COMMAND_MAP.PS_RESTART} --app=myapp --dyno-name=web.1`); }); it('should build correct command with all parameters', async () => { mocks.herokuRepl.executeCommand.resolves('Restarting web dynos... done\n'); await toolCallback({ app: 'myapp', 'dyno-name': 'web.1', 'process-type': 'web' }); expect(mocks.herokuRepl.executeCommand.calledOnce).to.be.true; expect(mocks.herokuRepl.executeCommand.firstCall.args[0]).to.equal(`${TOOL_COMMAND_MAP.PS_RESTART} --app=myapp --dyno-name=web.1 --process-type=web`); }); }); });