Skip to content

Conversation

@nixel2007
Copy link
Member

@nixel2007 nixel2007 commented Jan 2, 2026

Описание

Связанные задачи

Closes

Чеклист

Общие

  • Ветка PR обновлена из develop
  • Отладочные, закомментированные и прочие, не имеющие смысла участки кода удалены
  • Изменения покрыты тестами
  • Обязательные действия перед коммитом выполнены (запускал команду gradlew precommit)

Для диагностик

  • Описание диагностики заполнено для обоих языков (присутствуют файлы для обоих языков, для русского заполнено все подробно, перевод на английский можно опустить)

Дополнительно

Summary by CodeRabbit

  • Bug Fixes

    • Improved document closure reliability: shutdown now more robustly waits for worker termination and logs when termination fails or is interrupted, ensuring pending edits are flushed before close.
  • Tests

    • Added tests validating that closing a document correctly synchronizes with in-flight and pending changes and with executor shutdown.

✏️ Tip: You can customize this high-level summary in your review settings.

Copilot AI review requested due to automatic review settings January 2, 2026 08:30
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 2, 2026

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

didClose in BSLTextDocumentService now waits for the document executor to terminate, and if it times out calls shutdownNow and waits an additional 1 second (AWAIT_FORCE_TERMINATION). InterruptedException handling also calls shutdownNow, waits the extra second, logs if termination fails, and preserves the thread interrupt status. Tests added to exercise close behavior.

Changes

Cohort / File(s) Summary
Executor shutdown / didClose
src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java
Added AWAIT_FORCE_TERMINATION = 1 and updated didClose to call shutdownNow() if initial awaitTermination times out, wait up to 1s more, log warnings on non-termination; on InterruptedException also invoke shutdownNow(), await the extra second, log failures, and restore interrupt status.
Tests for close semantics
src/test/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentServiceTest.java
Added three tests: didCloseWithPendingChanges, didCloseDuringActiveChange, and didCloseAwaitTerminationCompletes to verify close synchronizes with in-flight/pending changes and executor termination behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I nudged the runners to take their rest,
I waited once, then one more test,
A gentle nudge, a missing hum—
Now threads unwind; the logs go yum.
Hooray, the close completes at last!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ 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 accurately describes the main change: fixing a potential race condition during document closure in BSLTextDocumentService, which matches the enhanced shutdown handling and synchronization in the code changes.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f8abc95 and 9f00ce2.

📒 Files selected for processing (2)
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentServiceTest.java
🧰 Additional context used
📓 Path-based instructions (3)
src/main/java/**/*.java

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/main/java/**/*.java: Follow the Style Guide for code formatting and conventions
Use Lombok annotations to reduce boilerplate code and enable annotation processing in IDE
Write JavaDoc for public APIs and include comments for complex logic
Use meaningful, descriptive names for classes and methods following Java naming conventions
Optimize imports before committing; DO NOT optimize imports across the entire project unless specifically working on that task

Files:

  • src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java
src/**/*.java

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use Java 17 for language and follow Java naming conventions

Files:

  • src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentServiceTest.java
src/test/java/**/*Test.java

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Maintain or improve test coverage and use appropriate test frameworks (JUnit, AssertJ, Mockito)

Files:

  • src/test/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentServiceTest.java
🧠 Learnings (1)
📚 Learning: 2025-02-10T17:12:56.150Z
Learnt from: nixel2007
Repo: 1c-syntax/bsl-language-server PR: 3408
File: src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/ProtectedModuleDiagnostic.java:63-66
Timestamp: 2025-02-10T17:12:56.150Z
Learning: In BSL Language Server, `documentContext.getServerContext().getConfiguration()` is guaranteed to return a non-null value, making null checks unnecessary.

Applied to files:

  • src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: Agent
  • GitHub Check: CodeQL analysis (java)
  • GitHub Check: build (25, ubuntu-latest)
  • GitHub Check: build (25, macOS-latest)
  • GitHub Check: build (25, windows-latest)
  • GitHub Check: build (21, windows-latest)
  • GitHub Check: build (21, ubuntu-latest)
  • GitHub Check: build (17, ubuntu-latest)
  • GitHub Check: build (21, macOS-latest)
  • GitHub Check: build (17, windows-latest)
  • GitHub Check: build (17, macOS-latest)
  • GitHub Check: Benchmark
  • GitHub Check: Analyse
  • GitHub Check: build
  • GitHub Check: Analyze the repo with CodeSee
🔇 Additional comments (3)
src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java (2)

143-143: LGTM! Constant extracted for improved maintainability.

The AWAIT_FORCE_TERMINATION constant addresses the previous review feedback about hardcoded timeout values, making the code more maintainable and the timeout value more discoverable.


534-563: Excellent race condition mitigation with comprehensive logging.

The enhanced shutdown sequence properly addresses the previous review concerns:

  1. After shutdownNow(), the code now waits for AWAIT_FORCE_TERMINATION seconds and logs a warning if termination fails (lines 536-542)
  2. The InterruptedException handler now also waits for termination after shutdownNow(), logs warnings for both non-termination and subsequent interruptions, and preserves the interrupt status (lines 544-562)
  3. The comment on lines 534-535 clearly explains why waiting after shutdownNow() is necessary (the worker's finally block may still be flushing pending changes)

The nested try-catch structure is appropriately complex given the need to handle both graceful and forceful shutdown scenarios while maintaining proper thread interrupt semantics.

src/test/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentServiceTest.java (1)

204-289: Solid test coverage for close synchronization scenarios.

The three new tests address the previous review feedback about missing test coverage:

  1. didCloseWithPendingChanges (lines 204-236): Validates that closing with multiple queued changes completes successfully
  2. didCloseDuringActiveChange (lines 238-267): Validates that closing during an active change operation handles the race condition properly
  3. didCloseAwaitTerminationCompletes (lines 269-289): Validates that close waits for executor termination

These tests effectively cover the key scenarios for the race condition fix and verify that documents are properly closed after the shutdown sequence completes.


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.

Copy link
Member Author

@nixel2007 nixel2007 left a comment

Choose a reason for hiding this comment

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

/buildJar

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java (1)

531-546: Race condition fix is sound; consider these maintainability improvements.

The enhanced shutdown logic correctly addresses the race condition by ensuring worker threads complete cleanup operations before document closure. The nested try-catch for interrupt handling is correct and properly restores interrupt status.

Suggested improvements:

  1. Extract timeout constant: The 1-second timeout after shutdownNow() appears in two places (lines 536 and 541). Extract it as private static final long AWAIT_SHUTDOWN_NOW = 1; alongside AWAIT_CLOSE for consistency and maintainability.

  2. Add logging for diagnostics: When awaitTermination times out, add warning logs to help diagnose shutdown issues in production. The class has @Slf4j annotation available.

  3. Verify assumption: The comment referencing "finally block in worker may still be executing flushPendingChanges" accurately describes DocumentChangeExecutor.runWorker() (line 187), but consider adding a JavaDoc comment explaining the wait strategy for future maintainers.

💡 Example implementation
 private static final long AWAIT_CLOSE = 30;
+private static final long AWAIT_SHUTDOWN_NOW = 1;

 if (!docExecutor.awaitTermination(AWAIT_CLOSE, TimeUnit.SECONDS)) {
+  log.warn("Document executor did not terminate within {} seconds, forcing shutdown: {}", AWAIT_CLOSE, uri);
   docExecutor.shutdownNow();
-  docExecutor.awaitTermination(1, TimeUnit.SECONDS);
+  if (!docExecutor.awaitTermination(AWAIT_SHUTDOWN_NOW, TimeUnit.SECONDS)) {
+    log.warn("Document executor still running after shutdownNow: {}", uri);
+  }
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a99503a and 67104f4.

📒 Files selected for processing (1)
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java
🧰 Additional context used
📓 Path-based instructions (2)
src/main/java/**/*.java

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/main/java/**/*.java: Follow the Style Guide for code formatting and conventions
Use Lombok annotations to reduce boilerplate code and enable annotation processing in IDE
Write JavaDoc for public APIs and include comments for complex logic
Use meaningful, descriptive names for classes and methods following Java naming conventions
Optimize imports before committing; DO NOT optimize imports across the entire project unless specifically working on that task

Files:

  • src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java
src/**/*.java

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use Java 17 for language and follow Java naming conventions

Files:

  • src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java

Copy link
Contributor

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 fixes a potential race condition in BSLTextDocumentService.didClose() by ensuring the worker thread completes execution (including its finally block) before proceeding with document closure. The fix addresses scenarios where shutdownNow() is called but the worker's finally block might still be executing flushPendingChanges().

Key changes:

  • Added awaitTermination(1, TimeUnit.SECONDS) after shutdownNow() calls to wait for worker thread completion
  • Added nested try-catch in the InterruptedException handler to gracefully handle interruptions during the additional wait

Comment on lines 541 to 542
docExecutor.awaitTermination(1, TimeUnit.SECONDS);
} catch (InterruptedException ignored) {
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

If the awaitTermination call at line 541 returns false (indicating the worker thread did not terminate within 1 second after interrupt), the method proceeds to restore the interrupt flag and continue. This means the document closure continues while the worker thread might still be executing, potentially accessing shared state. Consider logging this condition to help diagnose issues where worker threads fail to terminate promptly.

Suggested change
docExecutor.awaitTermination(1, TimeUnit.SECONDS);
} catch (InterruptedException ignored) {
boolean terminated = docExecutor.awaitTermination(1, TimeUnit.SECONDS);
if (!terminated) {
log.warn(
"Document executor for URI {} did not terminate within 1 second after interrupt during document close",
uri
);
}
} catch (InterruptedException ignored) {
log.warn(
"Interrupted again while waiting for document executor for URI {} to terminate after shutdownNow",
uri
);

Copilot uses AI. Check for mistakes.
Comment on lines 535 to 541
docExecutor.awaitTermination(1, TimeUnit.SECONDS);
}
} catch (InterruptedException e) {
docExecutor.shutdownNow();
// Wait briefly for worker to finish after interrupt
try {
docExecutor.awaitTermination(1, TimeUnit.SECONDS);
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

The 1-second timeout for awaiting worker thread termination after shutdownNow is hardcoded in multiple locations (lines 535 and 541). Consider extracting this value to a named constant (e.g., AWAIT_FORCE_TERMINATION) to improve maintainability and make the timeout value more discoverable and adjustable.

Copilot uses AI. Check for mistakes.
docExecutor.shutdownNow();
// Must wait for worker thread to finish even after shutdownNow,
// because finally block in worker may still be executing flushPendingChanges
docExecutor.awaitTermination(1, TimeUnit.SECONDS);
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

If the awaitTermination call at line 535 returns false (indicating the worker thread did not terminate within 1 second), the method proceeds without any logging or additional handling. This means the document closure continues while the worker thread might still be executing flushPendingChanges in its finally block, potentially leading to the race condition this change aims to fix. Consider logging this condition or implementing additional handling to ensure safe cleanup.

Suggested change
docExecutor.awaitTermination(1, TimeUnit.SECONDS);
boolean terminated = docExecutor.awaitTermination(1, TimeUnit.SECONDS);
if (!terminated) {
log.warn(
"Document executor for URI {} did not terminate within the additional timeout after shutdownNow()",
uri
);
}

Copilot uses AI. Check for mistakes.
Comment on lines 533 to 546
// Must wait for worker thread to finish even after shutdownNow,
// because finally block in worker may still be executing flushPendingChanges
docExecutor.awaitTermination(1, TimeUnit.SECONDS);
}
} catch (InterruptedException e) {
docExecutor.shutdownNow();
// Wait briefly for worker to finish after interrupt
try {
docExecutor.awaitTermination(1, TimeUnit.SECONDS);
} catch (InterruptedException ignored) {
// Already interrupted, just restore flag
}
Thread.currentThread().interrupt();
}
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

The added concurrency logic for handling race conditions during document closure lacks test coverage. The existing didClose test at line 183 in BSLTextDocumentServiceTest.java is very basic and doesn't test the scenario where pending changes are being flushed when shutdown occurs. Consider adding tests for: (1) didClose with pending changes in the executor queue, (2) didClose during an active didChange operation, (3) behavior when awaitTermination timeout expires.

Copilot uses AI. Check for mistakes.
@nixel2007
Copy link
Member Author

@copilot посмотри замечания по ревью

Copy link
Contributor

Copilot AI commented Jan 2, 2026

@nixel2007 I've opened a new pull request, #3725, to work on those changes. Once the pull request is ready, I'll request review from you.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 2, 2026

Test Results

 2 808 files  ±0   2 808 suites  ±0   51m 50s ⏱️ - 1m 36s
 1 151 tests ±0   1 151 ✅ ±0  0 💤 ±0  0 ❌ ±0 
10 359 runs  ±0  10 359 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit f8abc95. ± Comparison against base commit a11189a.

This pull request removes 8 and adds 4 tests. Note that renamed tests count towards both.
#, count=1
, count=0
, count=1
A, count=1
com.github._1c_syntax.bsl.languageserver.diagnostics.MetadataObjectNameLengthDiagnosticTest ‑ [2] content=
com.github._1c_syntax.bsl.languageserver.diagnostics.MetadataObjectNameLengthDiagnosticTest ‑ [6] content=
com.github._1c_syntax.bsl.languageserver.diagnostics.MetadataObjectNameLengthDiagnosticTest ‑ [7] content=#
com.github._1c_syntax.bsl.languageserver.diagnostics.MetadataObjectNameLengthDiagnosticTest ‑ [8] content=
com.github._1c_syntax.bsl.languageserver.diagnostics.MetadataObjectNameLengthDiagnosticTest ‑ [2] content=
, count=0
com.github._1c_syntax.bsl.languageserver.diagnostics.MetadataObjectNameLengthDiagnosticTest ‑ [6] content=
A, count=1
com.github._1c_syntax.bsl.languageserver.diagnostics.MetadataObjectNameLengthDiagnosticTest ‑ [7] content=#
, count=1
com.github._1c_syntax.bsl.languageserver.diagnostics.MetadataObjectNameLengthDiagnosticTest ‑ [8] content=
#, count=1

♻️ This comment has been updated with latest results.

Copy link
Contributor

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

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

Comment on lines +269 to +289
@Test
void didCloseAwaitTerminationCompletes() throws IOException {
// given - open a document
var textDocumentItem = getTextDocumentItem();
var didOpenParams = new DidOpenTextDocumentParams(textDocumentItem);
textDocumentService.didOpen(didOpenParams);

var uri = textDocumentItem.getUri();
var documentContext = serverContext.getDocumentUnsafe(uri);
assertThat(documentContext).isNotNull();
assertThat(serverContext.isDocumentOpened(documentContext)).isTrue();

// when - close the document (which should wait for executor to terminate)
var closeParams = new DidCloseTextDocumentParams();
closeParams.setTextDocument(new TextDocumentIdentifier(uri));
textDocumentService.didClose(closeParams);

// then - verify the document is properly closed
// The close should complete successfully even if executor needs time to terminate
assertThat(serverContext.isDocumentOpened(documentContext)).isFalse();
}
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

This test doesn't add meaningful test coverage beyond what didClose() already tests. The test opens and immediately closes a document without any changes, which doesn't exercise the race condition fix at all. The await termination logic being tested here is already covered by the normal document close flow. Consider removing this test or making it more specific by somehow verifying that the executor actually waited for termination (e.g., with mocking or timing assertions).

Copilot uses AI. Check for mistakes.
Comment on lines +534 to +561
// Must wait for worker thread to finish even after shutdownNow,
// because finally block in worker may still be executing flushPendingChanges
boolean terminated = docExecutor.awaitTermination(AWAIT_FORCE_TERMINATION, TimeUnit.SECONDS);
if (!terminated) {
LOGGER.warn(
"Document executor for URI {} did not terminate within the additional timeout after shutdownNow()",
uri
);
}
}
} catch (InterruptedException e) {
docExecutor.shutdownNow();
// Wait briefly for worker to finish after interrupt
try {
boolean terminated = docExecutor.awaitTermination(AWAIT_FORCE_TERMINATION, TimeUnit.SECONDS);
if (!terminated) {
LOGGER.warn(
"Document executor for URI {} did not terminate within {} seconds after interrupt during document close",
uri,
AWAIT_FORCE_TERMINATION
);
}
} catch (InterruptedException ignored) {
LOGGER.warn(
"Interrupted again while waiting for document executor for URI {} to terminate after shutdownNow",
uri
);
}
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

The logic for waiting after shutdownNow() is duplicated in two places - once inside the if block when normal termination times out (lines 534-542) and again in the catch block for InterruptedException (lines 547-561). Consider extracting this common logic into a private helper method to improve maintainability and reduce code duplication. The helper method could accept the URI and handle the awaitTermination call with appropriate logging.

Copilot uses AI. Check for mistakes.
AWAIT_FORCE_TERMINATION
);
}
} catch (InterruptedException ignored) {
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

The variable 'ignored' is declared but never used in the catch block. While this is a common pattern for documenting intentional suppression of exceptions, the variable should actually be named with an underscore prefix (e.g., '_') or simply omit the variable name entirely in modern Java, as the catch block already has explanatory logging that makes the intention clear.

Suggested change
} catch (InterruptedException ignored) {
} catch (InterruptedException _ignored) {

Copilot uses AI. Check for mistakes.
Comment on lines +204 to +236
@Test
void didCloseWithPendingChanges() throws IOException {
// given - open a document and make changes
var textDocumentItem = getTextDocumentItem();
var didOpenParams = new DidOpenTextDocumentParams(textDocumentItem);
textDocumentService.didOpen(didOpenParams);

var documentContext = serverContext.getDocumentUnsafe(textDocumentItem.getUri());
assertThat(documentContext).isNotNull();
assertThat(serverContext.isDocumentOpened(documentContext)).isTrue();

// when - submit multiple changes rapidly and then close immediately
var params = new DidChangeTextDocumentParams();
var uri = textDocumentItem.getUri();

for (int i = 0; i < 5; i++) {
params.setTextDocument(new VersionedTextDocumentIdentifier(uri, 2 + i));
var range = Ranges.create(0, 0, 0, 0);
var changeEvent = new TextDocumentContentChangeEvent(range, "// Change " + i + "\n");
List<TextDocumentContentChangeEvent> contentChanges = new ArrayList<>();
contentChanges.add(changeEvent);
params.setContentChanges(contentChanges);
textDocumentService.didChange(params);
}

// then - close should wait for pending changes to complete
var closeParams = new DidCloseTextDocumentParams();
closeParams.setTextDocument(new TextDocumentIdentifier(uri));
textDocumentService.didClose(closeParams);

// verify the document is closed
assertThat(serverContext.isDocumentOpened(documentContext)).isFalse();
}
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

The test submits changes synchronously in a loop and then immediately closes the document, but this doesn't effectively test the race condition the PR aims to fix. Since didChange() only queues changes asynchronously and returns immediately, all the changes are likely queued before close is called. The test would benefit from verifying that changes are actually being processed (e.g., by checking the final document content contains all expected changes) to confirm that the close operation properly waited for the pending changes to complete.

Copilot uses AI. Check for mistakes.
Comment on lines +238 to +267
@Test
void didCloseDuringActiveChange() throws IOException {
// given - open a document
var textDocumentItem = getTextDocumentItem();
var didOpenParams = new DidOpenTextDocumentParams(textDocumentItem);
textDocumentService.didOpen(didOpenParams);

var documentContext = serverContext.getDocumentUnsafe(textDocumentItem.getUri());
assertThat(documentContext).isNotNull();
assertThat(serverContext.isDocumentOpened(documentContext)).isTrue();

// when - submit a change
var params = new DidChangeTextDocumentParams();
var uri = textDocumentItem.getUri();
params.setTextDocument(new VersionedTextDocumentIdentifier(uri, 2));
var range = Ranges.create(0, 0, 0, 0);
var changeEvent = new TextDocumentContentChangeEvent(range, "// New content\n");
List<TextDocumentContentChangeEvent> contentChanges = new ArrayList<>();
contentChanges.add(changeEvent);
params.setContentChanges(contentChanges);
textDocumentService.didChange(params);

// then - close immediately while change may still be processing
var closeParams = new DidCloseTextDocumentParams();
closeParams.setTextDocument(new TextDocumentIdentifier(uri));
textDocumentService.didClose(closeParams);

// verify the document is closed
assertThat(serverContext.isDocumentOpened(documentContext)).isFalse();
}
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

This test is essentially the same as didCloseWithPendingChanges but with only a single change. It doesn't add much value since it tests the same code path. Consider either removing this test or making it distinct by introducing a more realistic scenario - for example, using Thread.sleep() or a CountDownLatch to ensure the close is called while the change is actually being processed in the executor thread, rather than just queued.

Copilot uses AI. Check for mistakes.
@sonarqubecloud
Copy link

sonarqubecloud bot commented Jan 2, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
0.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@nixel2007 nixel2007 disabled auto-merge January 2, 2026 10:56
@nixel2007 nixel2007 merged commit 4b3c193 into develop Jan 2, 2026
45 of 46 checks passed
@nixel2007 nixel2007 deleted the fix/possible-race-on-did-close branch January 2, 2026 10:56
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