-
Notifications
You must be signed in to change notification settings - Fork 121
Add logging and test coverage for document close race condition handling #3725
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -186,6 +186,93 @@ void didClose() { | |
| textDocumentService.didClose(params); | ||
| } | ||
|
|
||
| @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(); | ||
| } | ||
|
|
||
| @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(); | ||
| } | ||
|
Comment on lines
+223
to
+252
|
||
|
|
||
| @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(); | ||
| } | ||
|
Comment on lines
+254
to
+274
|
||
|
|
||
| @Test | ||
| void didSave() { | ||
| DidSaveTextDocumentParams params = new DidSaveTextDocumentParams(); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tests
didCloseWithPendingChangesanddidCloseDuringActiveChangemay have race conditions. After submitting document changes withdidChange(), the changes are processed asynchronously in the DocumentChangeExecutor's worker thread. ThedidClose()method should wait for these changes to complete, but the tests should verify that this waiting actually works correctly.Consider using
await()withatMost()(as done in other tests likedidChangeIncremental()at line 116) to verify that the document changes were actually applied before closing. This would make the tests more robust and actually test the race condition handling rather than just testing that close completes.