Skip to content

refactor(tests): reorganize integration tests into domain-based subdirectories - #409

Merged
16bit-ykiko merged 6 commits into
mainfrom
refactor/integration-tests
Apr 8, 2026
Merged

refactor(tests): reorganize integration tests into domain-based subdirectories#409
16bit-ykiko merged 6 commits into
mainfrom
refactor/integration-tests

Conversation

@16bit-ykiko

@16bit-ykiko 16bit-ykiko commented Apr 8, 2026

Copy link
Copy Markdown
Member

Summary

  • Extract shared test utilities into tests/integration/utils/ (client, workspace, assertions, wait, cache)
  • Migrate 12 test files into categorized subdirectories: lifecycle/, compilation/, features/, modules/, extensions/, stress/
  • Merge test_include_completion.py + test_import_completion.pyfeatures/test_completion.py
  • Remove stale directory-tree comments and section divider comments

Test plan

  • pytest --collect-only collects all 113 tests
  • All test module imports verified
  • pixi run format applied

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests
    • Reorganized integration suites: added new feature tests (completion, server) and removed older duplicated modules.
    • Centralized shared test utilities and assertion helpers for diagnostics, workspace operations, waiting/synchronization, and cache inspection.
  • Chores / Refactor
    • Standardized test client lifecycle and helper usage across suites for more reliable test flows.
    • Improved server session lifecycle handling for more predictable document/session resets during tests.

16bit-ykiko and others added 4 commits April 9, 2026 00:26
…rectories

Extract shared test utilities into tests/integration/utils/ (client, workspace,
assertions, wait, cache) and migrate 12 test files into categorized subdirectories:
lifecycle/, compilation/, features/, modules/, extensions/, stress/.

Merge include_completion + import_completion into features/test_completion.py.
All 113 tests collected successfully with zero import errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… conftest

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Apr 8, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Consolidates integration test utilities into tests/integration/utils, replaces many in-file test helpers with shared utilities and a common CliceClient, adds new feature-focused integration tests, removes several older test modules, and adjusts master_server open handling to reset existing sessions on reopen.

Changes

Cohort / File(s) Summary
Test utilities package
tests/integration/utils/__init__.py, tests/integration/utils/client.py, tests/integration/utils/assertions.py, tests/integration/utils/workspace.py, tests/integration/utils/wait.py, tests/integration/utils/cache.py
New shared integration utilities: centralized CliceClient, diagnostic assertion helpers, workspace helpers (doc, write_cdb, write_source, did_change), wait-for-recompile/index helpers, and cache inspection functions exported via __all__.
Conftest / fixtures
tests/conftest.py
Removed local CliceClient implementation and in-file helper logic; now imports shared CliceClient; added make_client(executable, workspace), async _shutdown_client(c) with public alias shutdown_client, and _generate_test_data_cdbs(data_dir); refactored test-data CDB generation.
New feature tests
tests/integration/features/test_completion.py, tests/integration/features/test_server.py
Added integration suites for include/module completion and comprehensive server feature/capability tests and lifecycles.
Compilation & cache tests
tests/integration/compilation/test_pch.py, tests/integration/compilation/test_persistent_cache.py, tests/integration/compilation/test_staleness.py
Refactored to use shared utilities (doc, did_change, wait_for_recompile) and assertion helpers (assert_clean_compile, assert_no_errors, assert_has_errors); removed duplicated inline CDB generation.
Indexing / feature request tests
tests/integration/features/test_index.py
Replaced local indexing/wait helpers with wait_for_index; swapped low-level LSP param construction for high-level client methods (definition_at, references_at, close, etc.).
Lifecycle / modules / stress tests
tests/integration/lifecycle/test_file_operation.py, tests/integration/modules/test_modules.py, tests/integration/stress/test_rapid_edit.py
Replaced inline LSP parameter construction with doc() and did_change() utilities; use client.close() and shared assertion/wait helpers.
Removed / consolidated tests
tests/integration/test_import_completion.py, tests/integration/test_include_completion.py, tests/integration/test_server.py
Deleted older test modules; coverage migrated into new feature-focused suites.
Server change
src/server/master_server.cpp
On DidOpenTextDocumentParams, when try_emplace(path_id) finds an existing entry, the existing Session is reset to Session{} before updating path/version/text and incrementing generation to clear stale state.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

"I hopped through files with fluffy paws,
Collected helpers, trimmed the straws.
One client now, no duplicate lairs,
Tests happier in tidy pairs.
🐇📚✨"

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.33% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately describes the main change: reorganizing integration tests into domain-based subdirectories, which is the primary refactoring objective throughout the PR.

✏️ 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 refactor/integration-tests

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: 7

🧹 Nitpick comments (9)
tests/integration/features/test_index.py (1)

144-144: Remove unnecessary f prefix from string literal.

This string has no placeholders, so the f prefix is extraneous.

♻️ Suggested fix
-    assert len(result) > 0, f"prepareTypeHierarchy returned empty"
+    assert len(result) > 0, "prepareTypeHierarchy returned empty"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/integration/features/test_index.py` at line 144, The assertion message
uses an unnecessary f-string; update the assertion in the test that checks
prepareTypeHierarchy (the line asserting len(result) > 0) to use a normal string
literal instead of an f-string (remove the leading `f` from
`"prepareTypeHierarchy returned empty"`), leaving the rest of the assertion
unchanged.
tests/integration/lifecycle/test_file_operation.py (1)

6-13: Remove unused import VersionedTextDocumentIdentifier.

After refactoring to use the did_change helper, VersionedTextDocumentIdentifier is no longer used directly in this file.

♻️ Suggested fix
 from lsprotocol.types import (
     CompletionParams,
     DidCloseTextDocumentParams,
     HoverParams,
     Position,
     SignatureHelpParams,
-    VersionedTextDocumentIdentifier,
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/integration/lifecycle/test_file_operation.py` around lines 6 - 13,
Remove the unused import VersionedTextDocumentIdentifier from the import list in
tests/integration/lifecycle/test_file_operation.py; specifically edit the import
block that currently lists CompletionParams, DidCloseTextDocumentParams,
HoverParams, Position, SignatureHelpParams, VersionedTextDocumentIdentifier and
delete VersionedTextDocumentIdentifier so only the used symbols remain.
tests/integration/features/test_completion.py (4)

6-14: Remove unused TextDocumentIdentifier import and use doc consistently.

doc is imported but TextDocumentIdentifier is used directly on line 180. For consistency with the rest of the refactored test suite, use doc(uri) instead.

♻️ Suggested fix for imports
 from lsprotocol.types import (
     HoverParams,
     Position,
-    TextDocumentIdentifier,
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/integration/features/test_completion.py` around lines 6 - 14, Remove
the unused TextDocumentIdentifier import and replace any direct usages of
TextDocumentIdentifier(...) with the helper doc(uri) to keep consistency with
the refactored tests; update the imports to only include HoverParams, Position,
and did_change (remove TextDocumentIdentifier) and change the creation site
(where TextDocumentIdentifier is used) to call doc(uri) instead so the test uses
the shared document helper.

188-191: Consider using the shared get_errors helper for consistency.

The error filtering logic duplicates what get_errors from tests.integration.utils.assertions already provides. Using the shared helper improves consistency and maintainability.

♻️ Suggested fix
+from tests.integration.utils.assertions import get_errors
+
 ...
 
     diags = client.diagnostics.get(uri, [])
     # Should have no errors if Math PCM was built successfully from buffer scan.
-    errors = [d for d in diags if d.severity == 1]
+    errors = get_errors(diags)
     assert len(errors) == 0, f"Expected no errors, got: {errors}"

Note: get_errors may need to be added to the __all__ exports in tests/integration/utils/__init__.py if not already exported.

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

In `@tests/integration/features/test_completion.py` around lines 188 - 191,
Replace the manual error filtering of diagnostics (the diags variable and the
errors list comprehension filtering for d.severity == 1) with the shared helper
get_errors from tests.integration.utils.assertions: call
get_errors(client.diagnostics, uri) or get_errors(diags) as appropriate and
assert its length is zero; if get_errors is not exported from
tests.integration.utils.__init__, add it to __all__ so the test can import it
consistently.

109-164: Import completion tests are missing document close calls.

The include completion tests (lines 17-106) properly close documents with client.close(uri), but the import completion tests (test_import_completion_basic, test_import_completion_with_prefix, test_import_completion_dotted_names) do not close the opened documents. This inconsistency could lead to resource leaks or flaky tests.

♻️ Suggested fix for test_import_completion_basic
     assert "A" in labels, f"Expected 'A' in completion labels, got: {labels}"
+
+    client.close(uri_b)

Apply similar fixes to test_import_completion_with_prefix and test_import_completion_dotted_names.

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

In `@tests/integration/features/test_completion.py` around lines 109 - 164, The
three import-completion tests (test_import_completion_basic,
test_import_completion_with_prefix, test_import_completion_dotted_names) open
documents with client.open/open_and_wait but never close them; add
client.close(uri) at the end of each test (use the uri returned when opening:
uri_b or uri_app) to mirror the include-completion tests and prevent resource
leaks/flakiness, ensuring each test closes any file it opened.

177-183: Use doc(uri) instead of TextDocumentIdentifier(uri=uri) for consistency.

The shared doc helper is already imported but not used here.

♻️ Suggested fix
     await client.text_document_hover_async(
         HoverParams(
-            text_document=TextDocumentIdentifier(uri=uri),
+            text_document=doc(uri),
             position=Position(line=0, character=0),
         )
     )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/integration/features/test_completion.py` around lines 177 - 183,
Replace the explicit TextDocumentIdentifier usage with the shared helper: in the
call to client.text_document_hover_async (the HoverParams construction), use
doc(uri) instead of TextDocumentIdentifier(uri=uri) so the test is consistent
with other tests; update the HoverParams argument accordingly
(HoverParams(text_document=doc(uri), position=Position(...))).
tests/integration/utils/__init__.py (1)

17-30: Consider sorting __all__ alphabetically.

The static analysis tool flags that __all__ is not sorted. While this doesn't affect functionality, sorting alphabetically improves readability and makes it easier to verify that all exports are listed.

♻️ Suggested fix
 __all__ = [
+    "assert_diagnostics_count",
+    "assert_has_errors",
+    "assert_no_errors",
     "CliceClient",
     "doc",
-    "write_cdb",
-    "write_source",
-    "assert_no_errors",
-    "assert_has_errors",
-    "assert_diagnostics_count",
-    "wait_for_recompile",
-    "wait_for_index",
     "list_pch_files",
     "list_pcm_files",
     "read_cache_json",
+    "wait_for_index",
+    "wait_for_recompile",
+    "write_cdb",
+    "write_source",
 ]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/integration/utils/__init__.py` around lines 17 - 30, The __all__ list
is not alphabetized; please reorder the entries in the __all__ variable so they
are sorted alphabetically (e.g., "CliceClient" then "assert_diagnostics_count",
"assert_has_errors", "assert_no_errors", "doc", "list_pch_files",
"list_pcm_files", "read_cache_json", "wait_for_index", "wait_for_recompile",
"write_cdb", "write_source") to satisfy the static analysis rule and improve
readability.
tests/integration/features/test_server.py (2)

18-19: Avoid hard-coding server version in an integration test.

Line 19 ("0.1.0") will break on every release even when behavior is correct. Prefer asserting non-empty version (or comparing against package metadata) instead of a fixed literal.

Suggested adjustment
 async def test_server_info(client, workspace):
     assert client.init_result.server_info.name == "clice"
-    assert client.init_result.server_info.version == "0.1.0"
+    assert client.init_result.server_info.version
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/integration/features/test_server.py` around lines 18 - 19, The test
currently hard-codes server version equality (assert
client.init_result.server_info.version == "0.1.0"), which will break on
releases; change the assertion to verify the version is non-empty or matches
package metadata instead. Update the assertion on
client.init_result.server_info.version to check truthiness/non-empty string (or
fetch the package/module version and compare against that value) while keeping
the existing name assertion (client.init_result.server_info.name == "clice")
unchanged. Ensure you reference and use client.init_result.server_info.version
in the updated assertion so the test remains robust across releases.

109-133: Several request tests don’t assert outcomes.

These calls only verify “no exception”, but currently look like behavioral tests. Either add explicit assertions (preferred) or assign to _ with a short comment clarifying smoke-test intent.

Also applies to: 161-177, 221-225

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

In `@tests/integration/features/test_server.py` around lines 109 - 133, Several
request tests (e.g., test_hover_before_compile, test_completion_request,
test_signature_help_request, test_definition_request) only call client.hover_at
/ client.completion_at / client.signature_help_at / client.definition_at and
don't assert anything; update each test to either assert expected properties on
the returned result (preferred) — for example check result is not None and
contains expected keys/fields — or explicitly assign the return to _ and add a
short comment like "# smoke test: ensure no exception" so intent is clear; apply
the same change pattern to the other affected tests referenced around the later
blocks (lines 161-177 and 221-225) that use the same client.*_at helpers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/integration/features/test_server.py`:
- Around line 137-141: Wrap the interaction/assertion sequence in
test_document_symbol_request (and the similar tests noted) with a try/finally so
client.close(uri) always runs: after obtaining uri via client.open_and_wait and
calling client.document_symbols (and performing assertions), ensure
client.close(uri) is invoked from a finally block to guarantee cleanup even when
assertions fail; update the tests at the other locations (lines 145-150,
153-158, 180-185, 214-249) using the same try/finally pattern around
client.open_and_wait, client.* calls, assertions, and client.close.
- Line 73: Replace the hardcoded await asyncio.sleep(...) calls in
tests/integration/features/test_server.py with the shared deterministic wait
helpers from the integration utils (e.g., wait_for_predicate or wait_for_event)
so tests wait on explicit conditions instead of time; for each sleep instance,
call the appropriate helper to poll/await a clear predicate (server
ready/connection established, recompile_complete flag, or notification queue
length > 0) with a sensible timeout, and remove the fixed-delay sleeps (the ones
currently at the three spots in this file) so the test asserts the specific
condition rather than sleeping.

In `@tests/integration/utils/cache.py`:
- Around line 31-38: The helper function list_tmp_files is defined but not
exported and appears unused; either add it to the package exports in
tests/integration/utils/__init__.py alongside list_pch_files, list_pcm_files,
and read_cache_json so it becomes public, or delete the unused function from
tests/integration/utils/cache.py if it’s unnecessary; locate the function by
name (list_tmp_files) and update the exports list or remove the function, then
run tests/grep to ensure no callers are relying on it.

In `@tests/integration/utils/client.py`:
- Around line 145-157: The helper open_and_wait currently awaits
text_document_hover_async(...) without a timeout, allowing a stalled server to
hang; wrap the hover request in asyncio.wait_for using the same timeout (or
compute a shared deadline and pass the remaining time to both calls) so the
hover call and the subsequent await asyncio.wait_for(event.wait(),
timeout=timeout) share the same deadline; update open_and_wait to call await
asyncio.wait_for(self.text_document_hover_async(...), timeout=timeout) (or
compute remaining_time after the hover to pass into event.wait()) to ensure both
operations time out predictably.
- Around line 80-85: The tests decode URIs before sending protocol messages
which breaks LSP document matching; update _normalize_uri and path_to_uri so
protocol-facing methods return the percent-encoded URI (i.e., remove or avoid
calling unquote for values returned to callers) and use _diagnostics_key(uri)
only when indexing/looking up self.diagnostics and self.diagnostics_events (keep
returned/propagated URIs percent-encoded). Also in open_and_wait wrap the
hover_async(...) call with asyncio.wait_for(..., timeout) (use the same timeout
already applied to event.wait()) so the hover request respects the timeout;
adjust callers that expect decoded paths to perform local filesystem decoding
only where needed.

In `@tests/integration/utils/wait.py`:
- Around line 30-56: The wait_for_index helper can exceed its timeout because
client.text_document_hover_async and client.workspace_symbol_async calls are
unbounded; update wait_for_index to compute a deadline (e.g., using
time.monotonic() + timeout) and before each await compute remaining = deadline -
now and return False if remaining <= 0, then wrap both
client.text_document_hover_async(...) and client.workspace_symbol_async(...)
calls with asyncio.wait_for(..., timeout=remaining) and handle
asyncio.TimeoutError by returning False (or continuing the loop for symbol polls
as appropriate) so every external request is bounded by the overall timeout;
refer to wait_for_index, client.text_document_hover_async, and
client.workspace_symbol_async to locate the changes.
- Around line 13-27: wait_for_recompile currently awaits
client.text_document_hover_async without a timeout so the helper can hang before
reaching the timed diagnostics wait; wrap the hover call in asyncio.wait_for
(use asyncio.wait_for(client.text_document_hover_async(...), timeout=timeout))
and measure elapsed time (e.g., start = loop.time()) to compute remaining =
timeout - elapsed, then call await asyncio.wait_for(event.wait(),
timeout=remaining) (and if remaining <= 0 raise/timeout immediately) so both
hover and diagnostics are bounded and share the original timeout; update
references: wait_for_recompile, client.text_document_hover_async, event.wait,
HoverParams, and asyncio.wait_for.

---

Nitpick comments:
In `@tests/integration/features/test_completion.py`:
- Around line 6-14: Remove the unused TextDocumentIdentifier import and replace
any direct usages of TextDocumentIdentifier(...) with the helper doc(uri) to
keep consistency with the refactored tests; update the imports to only include
HoverParams, Position, and did_change (remove TextDocumentIdentifier) and change
the creation site (where TextDocumentIdentifier is used) to call doc(uri)
instead so the test uses the shared document helper.
- Around line 188-191: Replace the manual error filtering of diagnostics (the
diags variable and the errors list comprehension filtering for d.severity == 1)
with the shared helper get_errors from tests.integration.utils.assertions: call
get_errors(client.diagnostics, uri) or get_errors(diags) as appropriate and
assert its length is zero; if get_errors is not exported from
tests.integration.utils.__init__, add it to __all__ so the test can import it
consistently.
- Around line 109-164: The three import-completion tests
(test_import_completion_basic, test_import_completion_with_prefix,
test_import_completion_dotted_names) open documents with
client.open/open_and_wait but never close them; add client.close(uri) at the end
of each test (use the uri returned when opening: uri_b or uri_app) to mirror the
include-completion tests and prevent resource leaks/flakiness, ensuring each
test closes any file it opened.
- Around line 177-183: Replace the explicit TextDocumentIdentifier usage with
the shared helper: in the call to client.text_document_hover_async (the
HoverParams construction), use doc(uri) instead of
TextDocumentIdentifier(uri=uri) so the test is consistent with other tests;
update the HoverParams argument accordingly (HoverParams(text_document=doc(uri),
position=Position(...))).

In `@tests/integration/features/test_index.py`:
- Line 144: The assertion message uses an unnecessary f-string; update the
assertion in the test that checks prepareTypeHierarchy (the line asserting
len(result) > 0) to use a normal string literal instead of an f-string (remove
the leading `f` from `"prepareTypeHierarchy returned empty"`), leaving the rest
of the assertion unchanged.

In `@tests/integration/features/test_server.py`:
- Around line 18-19: The test currently hard-codes server version equality
(assert client.init_result.server_info.version == "0.1.0"), which will break on
releases; change the assertion to verify the version is non-empty or matches
package metadata instead. Update the assertion on
client.init_result.server_info.version to check truthiness/non-empty string (or
fetch the package/module version and compare against that value) while keeping
the existing name assertion (client.init_result.server_info.name == "clice")
unchanged. Ensure you reference and use client.init_result.server_info.version
in the updated assertion so the test remains robust across releases.
- Around line 109-133: Several request tests (e.g., test_hover_before_compile,
test_completion_request, test_signature_help_request, test_definition_request)
only call client.hover_at / client.completion_at / client.signature_help_at /
client.definition_at and don't assert anything; update each test to either
assert expected properties on the returned result (preferred) — for example
check result is not None and contains expected keys/fields — or explicitly
assign the return to _ and add a short comment like "# smoke test: ensure no
exception" so intent is clear; apply the same change pattern to the other
affected tests referenced around the later blocks (lines 161-177 and 221-225)
that use the same client.*_at helpers.

In `@tests/integration/lifecycle/test_file_operation.py`:
- Around line 6-13: Remove the unused import VersionedTextDocumentIdentifier
from the import list in tests/integration/lifecycle/test_file_operation.py;
specifically edit the import block that currently lists CompletionParams,
DidCloseTextDocumentParams, HoverParams, Position, SignatureHelpParams,
VersionedTextDocumentIdentifier and delete VersionedTextDocumentIdentifier so
only the used symbols remain.

In `@tests/integration/utils/__init__.py`:
- Around line 17-30: The __all__ list is not alphabetized; please reorder the
entries in the __all__ variable so they are sorted alphabetically (e.g.,
"CliceClient" then "assert_diagnostics_count", "assert_has_errors",
"assert_no_errors", "doc", "list_pch_files", "list_pcm_files",
"read_cache_json", "wait_for_index", "wait_for_recompile", "write_cdb",
"write_source") to satisfy the static analysis rule and improve readability.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 996ecb22-6f46-41e9-8151-9367301fc54b

📥 Commits

Reviewing files that changed from the base of the PR and between 2bbdf6c and 8407082.

📒 Files selected for processing (27)
  • tests/conftest.py
  • tests/integration/compilation/__init__.py
  • tests/integration/compilation/test_pch.py
  • tests/integration/compilation/test_persistent_cache.py
  • tests/integration/compilation/test_staleness.py
  • tests/integration/extensions/__init__.py
  • tests/integration/extensions/test_header_context.py
  • tests/integration/features/__init__.py
  • tests/integration/features/test_completion.py
  • tests/integration/features/test_index.py
  • tests/integration/features/test_server.py
  • tests/integration/lifecycle/__init__.py
  • tests/integration/lifecycle/test_file_operation.py
  • tests/integration/lifecycle/test_lifecycle.py
  • tests/integration/modules/__init__.py
  • tests/integration/modules/test_modules.py
  • tests/integration/stress/__init__.py
  • tests/integration/stress/test_rapid_edit.py
  • tests/integration/test_import_completion.py
  • tests/integration/test_include_completion.py
  • tests/integration/test_server.py
  • tests/integration/utils/__init__.py
  • tests/integration/utils/assertions.py
  • tests/integration/utils/cache.py
  • tests/integration/utils/client.py
  • tests/integration/utils/wait.py
  • tests/integration/utils/workspace.py
💤 Files with no reviewable changes (3)
  • tests/integration/test_import_completion.py
  • tests/integration/test_server.py
  • tests/integration/test_include_completion.py

Comment thread tests/integration/features/test_server.py
Comment thread tests/integration/features/test_server.py
Comment thread tests/integration/utils/cache.py
Comment thread tests/integration/utils/client.py
Comment thread tests/integration/utils/client.py
Comment thread tests/integration/utils/wait.py
Comment thread tests/integration/utils/wait.py

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/server/master_server.cpp (1)

311-320: ⚠️ Potential issue | 🟠 Major

Generation counter reset creates ABA race with in-flight compilations.

Resetting the session via Session{} resets generation to 0. After the subsequent generation++, it becomes 1. If an in-flight compilation from a previous open captured gen=1, the staleness check (sess->generation != gen) in the detached compilation task (compiler.cpp:727) will incorrectly pass, potentially applying old compilation results to new content.

Preserve the generation counter before resetting to maintain monotonicity:

Proposed fix
     auto [it, inserted] = sessions.try_emplace(path_id);
     auto& session = it->second;
     if(!inserted) {
         // DenseMap tombstone may retain stale data — reset to a fresh Session.
+        auto old_gen = session.generation;
         session = Session{};
+        session.generation = old_gen;
     }
     session.path_id = path_id;
     session.version = params.text_document.version;
     session.text = params.text_document.text;
     session.generation++;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/server/master_server.cpp` around lines 311 - 320, The reset of a Session
via session = Session{} wipes session.generation and can create an ABA race with
in-flight compilations (sess->generation vs gen). Fix by saving the current
generation before resetting (auto old_gen = session.generation), perform the
reset (session = Session{}), restore the saved generation (session.generation =
old_gen) and then apply the normal update/increment (session.generation++) along
with setting session.path_id, session.version and session.text; target the code
around sessions.try_emplace/path_id and Session to preserve monotonic generation
used by the detached compilation task check (sess->generation != gen).
♻️ Duplicate comments (2)
tests/integration/features/test_server.py (2)

105-108: ⚠️ Potential issue | 🟠 Major

Guarantee client.close(uri) with try/finally in document-open tests.

Across these ranges, close is not protected if an assertion or awaited request fails. Wrap open/use/assert flows in try/finally so cleanup always runs.

Suggested pattern
 async def test_document_symbol_request(client, workspace):
     uri, _ = await client.open_and_wait(workspace / "main.cpp")
-    result = await client.document_symbols(uri)
-    assert result is not None
-    client.close(uri)
+    try:
+        result = await client.document_symbols(uri)
+        assert result is not None
+    finally:
+        client.close(uri)

Also applies to: 111-120, 123-127, 130-134, 137-141, 144-149, 152-157, 160-165, 168-175, 178-185, 188-193, 221-256

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

In `@tests/integration/features/test_server.py` around lines 105 - 108, The test
currently calls uri, _ = await client.open_and_wait(workspace / "main.cpp") and
then client.close(uri) but leaves close unprotected if assertions or awaits
fail; wrap the open/use/assert sequence in a try/finally so client.close(uri)
always runs — i.e., after obtaining uri from client.open_and_wait(), perform
assertions and awaited operations inside a try block and call client.close(uri)
in the finally block (apply the same pattern to other similar ranges),
referencing the existing client.open_and_wait and client.close calls and the uri
variable.

75-75: ⚠️ Potential issue | 🟠 Major

Replace fixed sleeps with deterministic waits.

Line 75, Line 98–99, Line 201, and Line 208–210 use time-based delays, which makes these tests timing-sensitive and flaky under slow CI. Please wait on explicit conditions/events from shared integration utils instead of asyncio.sleep(...).

Also applies to: 98-99, 201-201, 208-210

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

In `@tests/integration/features/test_server.py` at line 75, Several tests use
fixed sleeps (await asyncio.sleep(...)) which causes flaky timing; replace each
sleep with deterministic waits on explicit conditions from the shared
integration utilities. Locate every occurrence of await asyncio.sleep(...) in
tests/integration/features/test_server.py (the instances called around the async
test flows) and replace them with calls to the appropriate shared integration
utility (for example wait_for_event, wait_until_condition,
wait_for_server_ready, or a client.wait_for_message) that checks the exact state
or event the test expects; ensure the new wait asserts a timeout and returns the
condition result so the test fails deterministically if the event never occurs.
Use the existing helper functions in the integration utils module rather than
sleeping, and match the awaited condition to the specific expectation (e.g.,
server ready, websocket message received, or background task completion).
🧹 Nitpick comments (1)
tests/integration/features/test_server.py (1)

123-133: Strengthen request tests with explicit response assertions.

These tests currently mostly validate “no exception thrown.” Add minimal contract assertions (e.g., expected type/non-empty fields when applicable) so regressions in response content are caught, not just transport success.

Also applies to: 137-140, 168-185

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

Outside diff comments:
In `@src/server/master_server.cpp`:
- Around line 311-320: The reset of a Session via session = Session{} wipes
session.generation and can create an ABA race with in-flight compilations
(sess->generation vs gen). Fix by saving the current generation before resetting
(auto old_gen = session.generation), perform the reset (session = Session{}),
restore the saved generation (session.generation = old_gen) and then apply the
normal update/increment (session.generation++) along with setting
session.path_id, session.version and session.text; target the code around
sessions.try_emplace/path_id and Session to preserve monotonic generation used
by the detached compilation task check (sess->generation != gen).

---

Duplicate comments:
In `@tests/integration/features/test_server.py`:
- Around line 105-108: The test currently calls uri, _ = await
client.open_and_wait(workspace / "main.cpp") and then client.close(uri) but
leaves close unprotected if assertions or awaits fail; wrap the open/use/assert
sequence in a try/finally so client.close(uri) always runs — i.e., after
obtaining uri from client.open_and_wait(), perform assertions and awaited
operations inside a try block and call client.close(uri) in the finally block
(apply the same pattern to other similar ranges), referencing the existing
client.open_and_wait and client.close calls and the uri variable.
- Line 75: Several tests use fixed sleeps (await asyncio.sleep(...)) which
causes flaky timing; replace each sleep with deterministic waits on explicit
conditions from the shared integration utilities. Locate every occurrence of
await asyncio.sleep(...) in tests/integration/features/test_server.py (the
instances called around the async test flows) and replace them with calls to the
appropriate shared integration utility (for example wait_for_event,
wait_until_condition, wait_for_server_ready, or a client.wait_for_message) that
checks the exact state or event the test expects; ensure the new wait asserts a
timeout and returns the condition result so the test fails deterministically if
the event never occurs. Use the existing helper functions in the integration
utils module rather than sleeping, and match the awaited condition to the
specific expectation (e.g., server ready, websocket message received, or
background task completion).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1227b22e-54cc-45a5-bafc-0d8b2e8f0ae5

📥 Commits

Reviewing files that changed from the base of the PR and between 8407082 and 39633ae.

📒 Files selected for processing (2)
  • src/server/master_server.cpp
  • tests/integration/features/test_server.py

…one bug)

llvm::DenseMap::erase marks slots as tombstones without clearing the
value. When try_emplace reuses a tombstone slot, the stale Session
data (ast_dirty=false) persists, causing ensure_compiled() to skip
recompilation on file reopen. Fix by explicitly resetting to a fresh
Session{} when try_emplace finds an existing entry.

Also fix test_hover_before_compile timeout on Windows Debug by removing
the 30s asyncio.wait_for wrapper — this test intentionally triggers a
first compilation via hover, which can exceed 30s in Debug builds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@16bit-ykiko
16bit-ykiko force-pushed the refactor/integration-tests branch from 39633ae to eea35aa Compare April 8, 2026 17:24

@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: 1

🧹 Nitpick comments (1)
tests/integration/features/test_server.py (1)

116-133: Consider adding assertions for completion, signature help, and definition tests.

These tests call the respective methods but don't assert on the results, making them purely "doesn't crash" smoke tests. While acceptable for initial coverage, consider adding basic assertions (e.g., result is not None or checking specific expected values) to validate actual behavior.

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

In `@tests/integration/features/test_server.py` around lines 116 - 133, Update the
three tests (test_completion_request, test_signature_help_request,
test_definition_request) to assert that the returned results are meaningful
instead of only calling the API: after calling client.completion_at,
client.signature_help_at, and client.definition_at, add assertions such as
result is not None and additional basic checks (e.g., for completion:
result.items or result['items'] is non-empty; for signature help:
result.signatures or result['signatures'] exists and length > 0; for definition:
result.location or result[0] is present) to ensure the methods actually return
expected structures. Keep the existing open_and_wait/close calls and make
assertions minimal and robust to small variations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/integration/features/test_server.py`:
- Around line 77-79: The test test_shutdown_exit calls
client.shutdown_async(None) directly but the client fixture already calls
_shutdown_client(c) in teardown, causing a double shutdown; remove the explicit
call to shutdown_async in test_shutdown_exit (or replace the test with
assertions that verify state after the fixture-managed teardown), or
alternatively create/use a dedicated fixture that skips the automatic
_shutdown_client teardown when you really need to exercise shutdown_async
explicitly; locate test_shutdown_exit and the client fixture/_shutdown_client to
implement the chosen fix.

---

Nitpick comments:
In `@tests/integration/features/test_server.py`:
- Around line 116-133: Update the three tests (test_completion_request,
test_signature_help_request, test_definition_request) to assert that the
returned results are meaningful instead of only calling the API: after calling
client.completion_at, client.signature_help_at, and client.definition_at, add
assertions such as result is not None and additional basic checks (e.g., for
completion: result.items or result['items'] is non-empty; for signature help:
result.signatures or result['signatures'] exists and length > 0; for definition:
result.location or result[0] is present) to ensure the methods actually return
expected structures. Keep the existing open_and_wait/close calls and make
assertions minimal and robust to small variations.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cd0dc53f-f36e-4dc1-8a83-77456ef31c19

📥 Commits

Reviewing files that changed from the base of the PR and between 39633ae and eea35aa.

📒 Files selected for processing (2)
  • src/server/master_server.cpp
  • tests/integration/features/test_server.py

Comment thread tests/integration/features/test_server.py
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@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 `@tests/integration/utils/__init__.py`:
- Around line 18-32: The __all__ export list in
tests/integration/utils/__init__.py is missing symbols and not alphabetized; add
the missing exports assert_clean_compile and, if present in workspace.py,
did_change to the list and then sort the entire __all__ alphabetically (apply
isort-style ordering) so entries like CliceClient, assert_clean_compile,
assert_diagnostics_count, assert_has_errors, assert_no_errors, did_change, doc,
list_pcm_files, list_pch_files, list_tmp_files, read_cache_json, wait_for_index,
wait_for_recompile, write_cdb, write_source appear in sorted order; verify
did_change exists before adding.
- Around line 3-16: Add the missing public exports by importing
assert_clean_compile from tests.integration.utils.assertions and did_change from
tests.integration.utils.workspace into the package __init__.py and then include
"assert_clean_compile" and "did_change" in the module's __all__ list (keep the
list sorted with the other names); update the existing import blocks for
assertions and workspace to include these symbols so tests can import them from
tests.integration.utils directly.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6ed5faf7-77b3-40f1-a8b9-c50658aab5cc

📥 Commits

Reviewing files that changed from the base of the PR and between eea35aa and 4a91b28.

📒 Files selected for processing (1)
  • tests/integration/utils/__init__.py

Comment thread tests/integration/utils/__init__.py
Comment thread tests/integration/utils/__init__.py
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