Skip to content

Expand MCP protocol coverage - #225

Merged
fernandotonon merged 2 commits into
masterfrom
codex/coverage-push-4
Mar 27, 2026
Merged

Expand MCP protocol coverage#225
fernandotonon merged 2 commits into
masterfrom
codex/coverage-push-4

Conversation

@fernandotonon

@fernandotonon fernandotonon commented Mar 27, 2026

Copy link
Copy Markdown
Owner

Summary

  • add protocol-level MCP server tests for JSON-RPC parsing, resources, tool definitions and stdin transport recovery
  • remove the CI-only skip from EditorViewport tests so the suite can execute on GitHub Actions
  • keep the new coverage focused on code paths that do not require optional AI/runtime features

Validation

  • local configure/build is running in
  • GitHub CI will validate the full matrix for this branch

Summary by CodeRabbit

  • Tests
    • Improved test reliability by removing environment-dependent skips.
    • Strengthened setup/teardown to ensure proper resource management.
    • Expanded protocol validation coverage for errors, message formats, ID handling, and initialization responses.
    • Added unit and integration tests for server protocol behavior, resource/tool listings, and recovery from malformed input.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Mar 27, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Removed CI/headless skip logic from EditorViewportTest::SetUp, added event processing in its TearDown, and introduced extensive MCPServer protocol tests using UNIX pipe I/O helpers to validate JSON-RPC framing, error handling, initialize responses, resource/tool handlers, and recovery from malformed input.

Changes

Cohort / File(s) Summary
Editor viewport test
src/EditorViewport_test.cpp
Removed conditional CI/headless GTEST_SKIP in SetUp; added app->processEvents() call after deleting mainWindow (guarded by if (app)) in TearDown.
MCP server protocol tests
src/MCPServer_test.cpp
Added test-only UNIX pipe I/O helpers, new MCPServerProtocolTest fixture, and many protocol-level gtests covering JSON parse errors (-32700), invalid request (-32600), method-not-found (-32601) id propagation, initialize response fields, resource/tool list handlers, notification behavior, and recovery from malformed headers.

Sequence Diagram(s)

sequenceDiagram
  participant Test as Test Harness
  participant PipeIn as OS Pipe (stdin)
  participant MCP as MCPServer
  participant PipeOut as OS Pipe (stdout)
  participant Parser as Test JSON Parser

  Test->>PipeIn: write framed message / malformed header
  PipeIn->>MCP: data available (onReadyRead)
  MCP->>MCP: parse framing, recover from bad header
  MCP->>PipeOut: write framed JSON-RPC response
  PipeOut->>Test: response bytes
  Test->>Parser: extract Content-Length body and parse JSON
  Parser-->>Test: structured result/assertions
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰
I tunneled through pipes of bytes and code,
Hopped past malformed headers on the road,
Framed messages tidy, responses bright,
Tests now dance in CI's morning light,
A floppy-eared cheer for protocol right! 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Expand MCP protocol coverage' directly and concisely summarizes the main objective: adding protocol-level MCP server tests and improving test coverage.
Description check ✅ Passed The description covers the main changes (MCP tests, EditorViewport skip removal) and validation approach, but omits formal Technical Details sections specified in the template.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/coverage-push-4

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/MCPServer_test.cpp`:
- Around line 3712-3714: The test currently hard-fails on OGRE init via
ASSERT_TRUE(tryInitOgre()); change it to skip when OGRE cannot initialize: call
tryInitOgre() and if it returns false, invoke the test skip mechanism (e.g.
GTEST_SKIP() with a short message) and return early so the rest of the test
(including createStandardOgreMaterials()) is not run; update the block around
tryInitOgre() / createStandardOgreMaterials() accordingly.
- Around line 14-18: Wrap POSIX-only code in MCPServer_test.cpp with a Windows
guard: surround the `#include` <unistd.h> and every POSIX call (pipe(), read(),
write(), close()) used in the SetUp() and TearDown() methods and the OnReadyRead
test with `#ifndef` Q_OS_WIN ... `#endif` so Windows builds skip them; in places
where behavior is required on Windows, replace or provide an alternative
implementation (e.g., use a named pipe or socket mock) inside the same guarded
blocks. Specifically update the include near the top, the pipe()/close() usage
in SetUp() and TearDown(), and the pipe()/write()/close() sequence in the
OnReadyRead test to be compiled only when Q_OS_WIN is not defined, and add
Windows-safe fallbacks or test skips for those tests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 93ca0780-390c-48b8-a2d5-5c9b3c25e1bf

📥 Commits

Reviewing files that changed from the base of the PR and between fce34b7 and 28c7ff4.

📒 Files selected for processing (2)
  • src/EditorViewport_test.cpp
  • src/MCPServer_test.cpp

Comment thread src/MCPServer_test.cpp
Comment on lines +14 to +18
#include <unistd.h>

#define private public
#include "MCPServer.h"
#undef private

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "POSIX transport APIs referenced from src/MCPServer_test.cpp:"
rg -n -C2 '<unistd\.h>|\b(pipe|read|write|close)\s*\(' src/MCPServer_test.cpp

echo
echo "Windows guards in src/MCPServer_test.cpp:"
rg -n -C1 'Q_OS_WIN' src/MCPServer_test.cpp || true

Repository: fernandotonon/QtMeshEditor

Length of output: 1578


Guard POSIX APIs with #ifndef Q_OS_WIN for Windows compatibility.

The file uses <unistd.h> and POSIX functions (pipe, read, write, close) without platform guards. These APIs are unavailable on Windows.

Wrap the include and all POSIX usage in:

  • Line 14: #include <unistd.h>
  • Lines 107–118: pipe() and close() in SetUp() and TearDown()
  • Lines 3749–3772: pipe(), write(), and close() in the OnReadyRead test

Either guard with #ifndef Q_OS_WIN or provide Windows-safe alternatives (e.g., named pipes or sockets).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/MCPServer_test.cpp` around lines 14 - 18, Wrap POSIX-only code in
MCPServer_test.cpp with a Windows guard: surround the `#include` <unistd.h> and
every POSIX call (pipe(), read(), write(), close()) used in the SetUp() and
TearDown() methods and the OnReadyRead test with `#ifndef` Q_OS_WIN ... `#endif` so
Windows builds skip them; in places where behavior is required on Windows,
replace or provide an alternative implementation (e.g., use a named pipe or
socket mock) inside the same guarded blocks. Specifically update the include
near the top, the pipe()/close() usage in SetUp() and TearDown(), and the
pipe()/write()/close() sequence in the OnReadyRead test to be compiled only when
Q_OS_WIN is not defined, and add Windows-safe fallbacks or test skips for those
tests.

Comment thread src/MCPServer_test.cpp
Comment on lines +3712 to +3714
ASSERT_TRUE(tryInitOgre());
createStandardOgreMaterials();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Skip this OGRE-backed test when headless init is unavailable.

Every other OGRE-dependent test in this file skips on tryInitOgre() failure. Hard-failing here makes the protocol suite brittle on runners where the display stack is unavailable even though the protocol path itself is fine.

💡 Suggested change
-    ASSERT_TRUE(tryInitOgre());
-    createStandardOgreMaterials();
+    if (!tryInitOgre()) {
+        GTEST_SKIP() << "Skipping: Ogre initialization failed";
+    }
+    createStandardOgreMaterials();
Based on learnings, "Tests must work under Xvfb (headless X11) — avoid assumptions about a real display."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/MCPServer_test.cpp` around lines 3712 - 3714, The test currently
hard-fails on OGRE init via ASSERT_TRUE(tryInitOgre()); change it to skip when
OGRE cannot initialize: call tryInitOgre() and if it returns false, invoke the
test skip mechanism (e.g. GTEST_SKIP() with a short message) and return early so
the rest of the test (including createStandardOgreMaterials()) is not run;
update the block around tryInitOgre() / createStandardOgreMaterials()
accordingly.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
src/MCPServer_test.cpp (2)

3712-3715: ⚠️ Potential issue | 🟠 Major

Skip instead of hard-failing when Ogre init is unavailable in headless CI.

This test still uses ASSERT_TRUE(tryInitOgre()); under headless runners it should skip like the rest of the suite instead of failing the job.

Based on learnings, "Tests must work under Xvfb (headless X11) — avoid assumptions about a real display".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/MCPServer_test.cpp` around lines 3712 - 3715, In
TEST_F(MCPServerProtocolTest, HandleResourcesReadSceneInfoReturnsSerializedText)
replace the hard assertion on tryInitOgre() with a conditional skip: call
tryInitOgre() and if it returns false invoke GTEST_SKIP() (or equivalent
test-skip macro) so the test is skipped in headless CI; update the block
surrounding tryInitOgre() / createStandardOgreMaterials() to use the skip path
rather than ASSERT_TRUE to avoid failing the job when Ogre cannot initialize.

14-15: ⚠️ Potential issue | 🔴 Critical

Guard POSIX-only APIs for Windows builds.

<unistd.h> and pipe/read/write/close are used without #ifndef Q_OS_WIN, which breaks Windows compilation for this test file.

As per coding guidelines, "Guard platform-specific APIs like <execinfo.h> (backtrace, backtrace_symbols_fd) and <unistd.h> (dup, STDERR_FILENO, SIGBUS) with #ifndef Q_OS_WIN for Windows compatibility".

Also applies to: 107-119, 3748-3772

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/MCPServer_test.cpp` around lines 14 - 15, The test file unconditionally
includes <unistd.h> and uses POSIX APIs (pipe, read, write, close, dup,
STDERR_FILENO, SIGBUS and related backtrace functions) which breaks Windows
builds; wrap the platform-specific include and every code block that calls
pipe/read/write/close (and any execinfo/backtrace usage) with `#ifndef` Q_OS_WIN
... `#endif` so the include and POSIX calls are excluded on Windows, and in the
guarded sections either skip the test or provide a Windows-safe alternative/stub
(use QSKIP or an `#else` stub) to preserve test semantics; specifically locate the
<unistd.h> include and the functions named pipe, read, write, close, dup,
backtrace, backtrace_symbols_fd and guard those regions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/MCPServer_test.cpp`:
- Around line 3760-3762: The test currently uses ASSERT_GT(write(inputPipe[1],
payload.constData(), payload.size()), 0) which permits partial writes and can
cause onReadyRead() to receive truncated frames; change the assertion to verify
the full payload was written by capturing the return value of write(...) into a
variable (e.g., ssize_t written) and asserting written == payload.size() so the
test fails on partial writes and eliminates flaky truncated-frame behavior when
writing the QByteArray payload constructed with
makeTransport(QJsonDocument(request).toJson(...)).
- Around line 40-49: readTransportMessage currently does a single blocking read
which can hang tests; change it to set readFd to non-blocking, then use a
bounded poll/select loop with a short timeout to wait for readability and
perform repeated reads appending into response until no more data or the overall
timeout elapses, handling EAGAIN/EWOULDBLOCK between reads, and finally restore
the original file flags; apply the same non-blocking poll/read pattern to the
other helper usages mentioned (lines 126-130 / related helper functions) so
processAndRead() cannot stall indefinitely.

---

Duplicate comments:
In `@src/MCPServer_test.cpp`:
- Around line 3712-3715: In TEST_F(MCPServerProtocolTest,
HandleResourcesReadSceneInfoReturnsSerializedText) replace the hard assertion on
tryInitOgre() with a conditional skip: call tryInitOgre() and if it returns
false invoke GTEST_SKIP() (or equivalent test-skip macro) so the test is skipped
in headless CI; update the block surrounding tryInitOgre() /
createStandardOgreMaterials() to use the skip path rather than ASSERT_TRUE to
avoid failing the job when Ogre cannot initialize.
- Around line 14-15: The test file unconditionally includes <unistd.h> and uses
POSIX APIs (pipe, read, write, close, dup, STDERR_FILENO, SIGBUS and related
backtrace functions) which breaks Windows builds; wrap the platform-specific
include and every code block that calls pipe/read/write/close (and any
execinfo/backtrace usage) with `#ifndef` Q_OS_WIN ... `#endif` so the include and
POSIX calls are excluded on Windows, and in the guarded sections either skip the
test or provide a Windows-safe alternative/stub (use QSKIP or an `#else` stub) to
preserve test semantics; specifically locate the <unistd.h> include and the
functions named pipe, read, write, close, dup, backtrace, backtrace_symbols_fd
and guard those regions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5b7ba530-da40-4960-aa1d-5e62341ca288

📥 Commits

Reviewing files that changed from the base of the PR and between 28c7ff4 and 1712824.

📒 Files selected for processing (1)
  • src/MCPServer_test.cpp

Comment thread src/MCPServer_test.cpp
Comment on lines +40 to +49
static QByteArray readTransportMessage(int readFd)
{
QByteArray response;
char buffer[4096];
ssize_t bytesRead = read(readFd, buffer, sizeof(buffer));
if (bytesRead > 0) {
response.append(buffer, bytesRead);
}
return response;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid blocking read() in transport helper; it can hang the test run.

readTransportMessage() does a single blocking read(). If processMessage() does not emit a frame (or emits later), processAndRead() can stall indefinitely and make CI flaky. Use non-blocking fd + bounded poll/read loop with timeout.

💡 Suggested fix
 static QByteArray readTransportMessage(int readFd)
 {
     QByteArray response;
     char buffer[4096];
-    ssize_t bytesRead = read(readFd, buffer, sizeof(buffer));
-    if (bytesRead > 0) {
-        response.append(buffer, bytesRead);
-    }
+    QElapsedTimer timer;
+    timer.start();
+    while (timer.elapsed() < 1000) {
+        ssize_t bytesRead = read(readFd, buffer, sizeof(buffer));
+        if (bytesRead > 0) {
+            response.append(buffer, bytesRead);
+            break;
+        }
+        QCoreApplication::processEvents(QEventLoop::AllEvents, 10);
+        QThread::msleep(5);
+    }
     return response;
 }

Also applies to: 126-130

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/MCPServer_test.cpp` around lines 40 - 49, readTransportMessage currently
does a single blocking read which can hang tests; change it to set readFd to
non-blocking, then use a bounded poll/select loop with a short timeout to wait
for readability and perform repeated reads appending into response until no more
data or the overall timeout elapses, handling EAGAIN/EWOULDBLOCK between reads,
and finally restore the original file flags; apply the same non-blocking
poll/read pattern to the other helper usages mentioned (lines 126-130 / related
helper functions) so processAndRead() cannot stall indefinitely.

Comment thread src/MCPServer_test.cpp
Comment on lines +3760 to +3762
const QByteArray payload = QByteArray("garbage\r\n\r\n") + makeTransport(QJsonDocument(request).toJson(QJsonDocument::Compact));
ASSERT_GT(write(inputPipe[1], payload.constData(), payload.size()), 0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Assert full pipe write to avoid truncated-frame flakes.

ASSERT_GT(write(...), 0) accepts partial writes; then onReadyRead() may parse a truncated payload intermittently. Assert written == payload.size().

💡 Suggested fix
-    ASSERT_GT(write(inputPipe[1], payload.constData(), payload.size()), 0);
+    const ssize_t written = write(inputPipe[1], payload.constData(), payload.size());
+    ASSERT_EQ(written, static_cast<ssize_t>(payload.size()));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const QByteArray payload = QByteArray("garbage\r\n\r\n") + makeTransport(QJsonDocument(request).toJson(QJsonDocument::Compact));
ASSERT_GT(write(inputPipe[1], payload.constData(), payload.size()), 0);
const QByteArray payload = QByteArray("garbage\r\n\r\n") + makeTransport(QJsonDocument(request).toJson(QJsonDocument::Compact));
const ssize_t written = write(inputPipe[1], payload.constData(), payload.size());
ASSERT_EQ(written, static_cast<ssize_t>(payload.size()));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/MCPServer_test.cpp` around lines 3760 - 3762, The test currently uses
ASSERT_GT(write(inputPipe[1], payload.constData(), payload.size()), 0) which
permits partial writes and can cause onReadyRead() to receive truncated frames;
change the assertion to verify the full payload was written by capturing the
return value of write(...) into a variable (e.g., ssize_t written) and asserting
written == payload.size() so the test fails on partial writes and eliminates
flaky truncated-frame behavior when writing the QByteArray payload constructed
with makeTransport(QJsonDocument(request).toJson(...)).

@sonarqubecloud

Copy link
Copy Markdown

@fernandotonon
fernandotonon merged commit 2d1c04b into master Mar 27, 2026
18 checks passed
@fernandotonon
fernandotonon deleted the codex/coverage-push-4 branch March 27, 2026 06:30
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.

1 participant