Skip to content

Conversation

Copy link

Copilot AI commented Dec 1, 2025

Q A
Bug fix? no
New feature? no
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets #2
License MIT
Doc PR N/A

Addresses code review feedback requesting test coverage for MCP server tools that were untested.

Added tests for:

  • pm2_restart_process - verifies restart action and structured response
  • pm2_reload_process - verifies zero-downtime reload behavior
  • pm2_flush_logs - verifies log flush for a process
  • pm2_reload_logs - verifies log rotation/reopen
  • pm2_dump - verifies process list persistence

Each test follows existing pattern: start echo process → call tool → assert structured response → cleanup.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

…ush_logs, pm2_reload_logs, and pm2_dump tools

Co-authored-by: elasticdotventures <35611074+elasticdotventures@users.noreply.github.com>
@elasticdotventures elasticdotventures marked this pull request as ready for review December 1, 2025 12:38
Copilot AI review requested due to automatic review settings December 1, 2025 12:38
Copilot AI changed the title [WIP] Address feedback on 'Add MCP MCP test harness' PR Add MCP test coverage for restart, reload, flush, reloadLogs, and dump tools Dec 1, 2025
@elasticdotventures elasticdotventures merged commit 2cf602c into feature/mcp-mcp-tests Dec 1, 2025
4 checks passed
@elasticdotventures elasticdotventures deleted the copilot/sub-pr-2 branch December 1, 2025 12:38
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds test coverage for five PM2 MCP server tools that were previously untested: pm2_restart_process, pm2_reload_process, pm2_flush_logs, pm2_reload_logs, and pm2_dump.

  • Adds comprehensive test coverage for process restart and reload operations
  • Adds test coverage for log management operations (flush and reload)
  • Adds test coverage for PM2's dump/persist functionality

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +244 to +251
await startEcho(name);
await new Promise(resolve => setTimeout(resolve, 200));

const dumpRes = await callToolWithTimeout('pm2_dump');
should(dumpRes.isError).not.equal(true);
should(dumpRes.structuredContent.action).eql('dump');

await callToolWithTimeout('pm2_delete_process', { process: name });
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cleanup logic in this test could fail to execute if any of the assertions above fail. Consider wrapping the test logic in a try-finally block to ensure the process is always deleted, preventing test pollution:

it('pm2_dump persists the current process list', async () => {
  const name = 'mcp-dump-test';
  try {
    await startEcho(name);
    await new Promise(resolve => setTimeout(resolve, 200));

    const dumpRes = await callToolWithTimeout('pm2_dump');
    should(dumpRes.isError).not.equal(true);
    should(dumpRes.structuredContent.action).eql('dump');
  } finally {
    await callToolWithTimeout('pm2_delete_process', { process: name });
  }
});
Suggested change
await startEcho(name);
await new Promise(resolve => setTimeout(resolve, 200));
const dumpRes = await callToolWithTimeout('pm2_dump');
should(dumpRes.isError).not.equal(true);
should(dumpRes.structuredContent.action).eql('dump');
await callToolWithTimeout('pm2_delete_process', { process: name });
try {
await startEcho(name);
await new Promise(resolve => setTimeout(resolve, 200));
const dumpRes = await callToolWithTimeout('pm2_dump');
should(dumpRes.isError).not.equal(true);
should(dumpRes.structuredContent.action).eql('dump');
} finally {
await callToolWithTimeout('pm2_delete_process', { process: name });
}

Copilot uses AI. Check for mistakes.
Comment on lines +191 to +200
await startEcho(name);
await new Promise(resolve => setTimeout(resolve, 200));

const restartRes = await callToolWithTimeout('pm2_restart_process', { process: name });
should(restartRes.isError).not.equal(true);
should(restartRes.structuredContent.action).eql('restart');
should(restartRes.structuredContent.process).eql(name);
should(restartRes.structuredContent.processes).be.an.Array();

await callToolWithTimeout('pm2_delete_process', { process: name });
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cleanup logic in this test could fail to execute if any of the assertions above fail. Consider wrapping the test logic in a try-finally block to ensure the process is always deleted, preventing test pollution:

it('pm2_restart_process restarts a running process', async () => {
  const name = 'mcp-restart-test';
  try {
    await startEcho(name);
    await new Promise(resolve => setTimeout(resolve, 200));

    const restartRes = await callToolWithTimeout('pm2_restart_process', { process: name });
    should(restartRes.isError).not.equal(true);
    should(restartRes.structuredContent.action).eql('restart');
    should(restartRes.structuredContent.process).eql(name);
    should(restartRes.structuredContent.processes).be.an.Array();
  } finally {
    await callToolWithTimeout('pm2_delete_process', { process: name });
  }
});
Suggested change
await startEcho(name);
await new Promise(resolve => setTimeout(resolve, 200));
const restartRes = await callToolWithTimeout('pm2_restart_process', { process: name });
should(restartRes.isError).not.equal(true);
should(restartRes.structuredContent.action).eql('restart');
should(restartRes.structuredContent.process).eql(name);
should(restartRes.structuredContent.processes).be.an.Array();
await callToolWithTimeout('pm2_delete_process', { process: name });
try {
await startEcho(name);
await new Promise(resolve => setTimeout(resolve, 200));
const restartRes = await callToolWithTimeout('pm2_restart_process', { process: name });
should(restartRes.isError).not.equal(true);
should(restartRes.structuredContent.action).eql('restart');
should(restartRes.structuredContent.process).eql(name);
should(restartRes.structuredContent.processes).be.an.Array();
} finally {
await callToolWithTimeout('pm2_delete_process', { process: name });
}

Copilot uses AI. Check for mistakes.
Comment on lines +205 to +214
await startEcho(name);
await new Promise(resolve => setTimeout(resolve, 200));

const reloadRes = await callToolWithTimeout('pm2_reload_process', { process: name });
should(reloadRes.isError).not.equal(true);
should(reloadRes.structuredContent.action).eql('reload');
should(reloadRes.structuredContent.process).eql(name);
should(reloadRes.structuredContent.processes).be.an.Array();

await callToolWithTimeout('pm2_delete_process', { process: name });
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cleanup logic in this test could fail to execute if any of the assertions above fail. Consider wrapping the test logic in a try-finally block to ensure the process is always deleted, preventing test pollution:

it('pm2_reload_process reloads a running process', async () => {
  const name = 'mcp-reload-test';
  try {
    await startEcho(name);
    await new Promise(resolve => setTimeout(resolve, 200));

    const reloadRes = await callToolWithTimeout('pm2_reload_process', { process: name });
    should(reloadRes.isError).not.equal(true);
    should(reloadRes.structuredContent.action).eql('reload');
    should(reloadRes.structuredContent.process).eql(name);
    should(reloadRes.structuredContent.processes).be.an.Array();
  } finally {
    await callToolWithTimeout('pm2_delete_process', { process: name });
  }
});
Suggested change
await startEcho(name);
await new Promise(resolve => setTimeout(resolve, 200));
const reloadRes = await callToolWithTimeout('pm2_reload_process', { process: name });
should(reloadRes.isError).not.equal(true);
should(reloadRes.structuredContent.action).eql('reload');
should(reloadRes.structuredContent.process).eql(name);
should(reloadRes.structuredContent.processes).be.an.Array();
await callToolWithTimeout('pm2_delete_process', { process: name });
try {
await startEcho(name);
await new Promise(resolve => setTimeout(resolve, 200));
const reloadRes = await callToolWithTimeout('pm2_reload_process', { process: name });
should(reloadRes.isError).not.equal(true);
should(reloadRes.structuredContent.action).eql('reload');
should(reloadRes.structuredContent.process).eql(name);
should(reloadRes.structuredContent.processes).be.an.Array();
} finally {
await callToolWithTimeout('pm2_delete_process', { process: name });
}

Copilot uses AI. Check for mistakes.
Comment on lines +219 to +227
await startEcho(name);
await new Promise(resolve => setTimeout(resolve, 200));

const flushRes = await callToolWithTimeout('pm2_flush_logs', { process: name });
should(flushRes.isError).not.equal(true);
should(flushRes.structuredContent.action).eql('flush');
should(flushRes.structuredContent.process).eql(name);

await callToolWithTimeout('pm2_delete_process', { process: name });
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cleanup logic in this test could fail to execute if any of the assertions above fail. Consider wrapping the test logic in a try-finally block to ensure the process is always deleted, preventing test pollution:

it('pm2_flush_logs flushes log files for a process', async () => {
  const name = 'mcp-flush-test';
  try {
    await startEcho(name);
    await new Promise(resolve => setTimeout(resolve, 200));

    const flushRes = await callToolWithTimeout('pm2_flush_logs', { process: name });
    should(flushRes.isError).not.equal(true);
    should(flushRes.structuredContent.action).eql('flush');
    should(flushRes.structuredContent.process).eql(name);
  } finally {
    await callToolWithTimeout('pm2_delete_process', { process: name });
  }
});
Suggested change
await startEcho(name);
await new Promise(resolve => setTimeout(resolve, 200));
const flushRes = await callToolWithTimeout('pm2_flush_logs', { process: name });
should(flushRes.isError).not.equal(true);
should(flushRes.structuredContent.action).eql('flush');
should(flushRes.structuredContent.process).eql(name);
await callToolWithTimeout('pm2_delete_process', { process: name });
try {
await startEcho(name);
await new Promise(resolve => setTimeout(resolve, 200));
const flushRes = await callToolWithTimeout('pm2_flush_logs', { process: name });
should(flushRes.isError).not.equal(true);
should(flushRes.structuredContent.action).eql('flush');
should(flushRes.structuredContent.process).eql(name);
} finally {
await callToolWithTimeout('pm2_delete_process', { process: name });
}

Copilot uses AI. Check for mistakes.
Comment on lines +232 to +239
await startEcho(name);
await new Promise(resolve => setTimeout(resolve, 200));

const reloadLogsRes = await callToolWithTimeout('pm2_reload_logs');
should(reloadLogsRes.isError).not.equal(true);
should(reloadLogsRes.structuredContent.action).eql('reloadLogs');

await callToolWithTimeout('pm2_delete_process', { process: name });
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cleanup logic in this test could fail to execute if any of the assertions above fail. Consider wrapping the test logic in a try-finally block to ensure the process is always deleted, preventing test pollution:

it('pm2_reload_logs rotates and reopens log files', async () => {
  const name = 'mcp-reloadlogs-test';
  try {
    await startEcho(name);
    await new Promise(resolve => setTimeout(resolve, 200));

    const reloadLogsRes = await callToolWithTimeout('pm2_reload_logs');
    should(reloadLogsRes.isError).not.equal(true);
    should(reloadLogsRes.structuredContent.action).eql('reloadLogs');
  } finally {
    await callToolWithTimeout('pm2_delete_process', { process: name });
  }
});
Suggested change
await startEcho(name);
await new Promise(resolve => setTimeout(resolve, 200));
const reloadLogsRes = await callToolWithTimeout('pm2_reload_logs');
should(reloadLogsRes.isError).not.equal(true);
should(reloadLogsRes.structuredContent.action).eql('reloadLogs');
await callToolWithTimeout('pm2_delete_process', { process: name });
try {
await startEcho(name);
await new Promise(resolve => setTimeout(resolve, 200));
const reloadLogsRes = await callToolWithTimeout('pm2_reload_logs');
should(reloadLogsRes.isError).not.equal(true);
should(reloadLogsRes.structuredContent.action).eql('reloadLogs');
} finally {
await callToolWithTimeout('pm2_delete_process', { process: name });
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants