Repository navigation
Searching tests cause freezes in big multi-module projects with junit 5 #1915
Description
related to #1203
You can use my open source project to reproduce it -- it's contain dozen maven modules, 2 millions loc, 9000 junit4 and junit5 tests, and already preconfigured and optimized with dev container (vscode and java tools inside, it also include instruction to setup and first run command):
Main problem:
- if you run tests from the root module (mage-tests) -- you will see popup "searching tests" message -- it's take 100-150+ seconds on any runs (cold and hot);
- single tests or small "folders" starting fast;
Dump collect by command (call it while "searching tests"):
jstack $(pgrep -f equinox.launcher) > jdtls-hang.txt
After some dumps research it was found the root of the problem: JUnit5TestFinder process. It's try to scan and construct full AST tree and fail on big amount of files. JUnit4TestFinder works too fast and miss from the dumps.
JUnit5TestFinder.internalIsTest()
WeakHashSet.cleanupGarbageCollectedValues
→ WeakHashSet.add
→ DeduplicationUtil.toString (locked WeakHashSet)
→ SearchableEnvironment.findType
→ ...
dump 1 example:
"ForkJoinPool.commonPool-worker-5" #337 [2445] daemon prio=5 os_prio=0 cpu=22747.59ms elapsed=184.51s tid=0x0000ffff140010f0 nid=2445 runnable
java.lang.Thread.State: RUNNABLE
at org.eclipse.jdt.internal.compiler.parser.Scanner.jumpOverMethodBody(Scanner.java:2247)
at org.eclipse.jdt.internal.compiler.parser.Scanner.getNextToken0(Scanner.java:1286)
at org.eclipse.jdt.internal.compiler.parser.Parser.dietParse(Parser.java:10308)
at org.eclipse.jdt.internal.compiler.Compiler.accept(Compiler.java:220)
at org.eclipse.jdt.core.dom.CompilationUnitResolver.accept(CompilationUnitResolver.java:230)
- locked <0x00000007aadbb700> (a org.eclipse.jdt.core.dom.CompilationUnitResolver)
at org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment.askForType(LookupEnvironment.java:434)
...
at org.eclipse.jdt.internal.compiler.lookup.ClassScope.connectTypeHierarchy(ClassScope.java:1394)
at org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment.completeTypeBindings(LookupEnvironment.java:612)
at org.eclipse.jdt.internal.compiler.Compiler.internalBeginToCompile(Compiler.java:787)
at org.eclipse.jdt.core.dom.CompilationUnitResolver.resolve(CompilationUnitResolver.java:1240)
at org.eclipse.jdt.core.dom.ASTParser.internalCreateASTCached(ASTParser.java:1412)
at org.eclipse.jdt.core.dom.ASTParser.createAST(ASTParser.java:933)
at org.eclipse.jdt.internal.junit.launcher.JUnit5TestFinder.internalIsTest(JUnit5TestFinder.java:271)
at org.eclipse.jdt.internal.junit.launcher.JUnit5TestFinder.findTestsInContainer(JUnit5TestFinder.java:221)
at com.microsoft.java.test.plugin.searcher.JUnit5TestSearcher.findTestItemsInContainer(JUnit5TestSearcher.java:130)
at com.microsoft.java.test.plugin.util.TestSearchUtils.findTestPackagesAndTypes(TestSearchUtils.java:169)
at com.microsoft.java.test.plugin.handler.TestDelegateCommandHandler.executeCommand(TestDelegateCommandHandler.java:61)
dump 2 example:
"ForkJoinPool.commonPool-worker-8" #340 [2448] daemon prio=5 os_prio=0 cpu=22085.22ms elapsed=184.51s tid=0x0000fffeec001b30 nid=2448 runnable
java.lang.Thread.State: RUNNABLE
at org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser.commentParse(AbstractCommentParser.java:225)
at org.eclipse.jdt.internal.compiler.parser.JavadocParser.checkDeprecation(JavadocParser.java:117)
...
at org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding.methods(SourceTypeBinding.java:1770)
at org.eclipse.jdt.internal.compiler.lookup.MethodVerifier.computeInheritedMethods(MethodVerifier.java:543)
at org.eclipse.jdt.internal.compiler.lookup.MethodVerifier.verify(MethodVerifier.java:1012)
at org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding.verifyMethods(SourceTypeBinding.java:2830)
at org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope.verifyMethods(CompilationUnitScope.java:1025)
at org.eclipse.jdt.core.dom.CompilationUnitResolver.resolve(CompilationUnitResolver.java:1307)
at org.eclipse.jdt.core.dom.ASTParser.createAST(ASTParser.java:933)
at org.eclipse.jdt.internal.junit.launcher.JUnit5TestFinder.internalIsTest(JUnit5TestFinder.java:271)
at org.eclipse.jdt.internal.junit.launcher.JUnit5TestFinder.findTestsInContainer(JUnit5TestFinder.java:221)
at com.microsoft.java.test.plugin.searcher.JUnit5TestSearcher.findTestItemsInContainer(JUnit5TestSearcher.java:130)
at com.microsoft.java.test.plugin.util.TestSearchUtils.findTestPackagesAndTypes(TestSearchUtils.java:169)
at com.microsoft.java.test.plugin.handler.TestDelegateCommandHandler.executeCommand(TestDelegateCommandHandler.java:61)
dump 3 example
"ForkJoinPool.commonPool-worker-5" #337 [2445] daemon prio=5 os_prio=0 cpu=52162.83ms elapsed=609.17s tid=0x0000ffff140010f0 nid=2445 runnable
java.lang.Thread.State: RUNNABLE
at org.eclipse.jdt.internal.core.util.WeakHashSet.cleanupGarbageCollectedValues(WeakHashSet.java:123)
at org.eclipse.jdt.internal.core.util.WeakHashSet.add(WeakHashSet.java:78)
at org.eclipse.jdt.internal.core.util.DeduplicationUtil.toString(DeduplicationUtil.java:46)
- locked <0x000000070209e980> (a org.eclipse.jdt.internal.core.util.WeakHashSet)
at org.eclipse.jdt.internal.core.SearchableEnvironment.findType(SearchableEnvironment.java:576)
at org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment.askForType(LookupEnvironment.java:386)
at org.eclipse.jdt.internal.compiler.lookup.MethodVerifier.computeInheritedMethods(MethodVerifier.java:543)
at org.eclipse.jdt.internal.compiler.lookup.MethodVerifier.verify(MethodVerifier.java:1012)
at org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding.verifyMethods(SourceTypeBinding.java:2830)
at org.eclipse.jdt.core.dom.CompilationUnitResolver.resolve(CompilationUnitResolver.java:1307)
at org.eclipse.jdt.core.dom.ASTParser.createAST(ASTParser.java:933)
at org.eclipse.jdt.internal.junit.launcher.JUnit5TestFinder.internalIsTest(JUnit5TestFinder.java:271)
at org.eclipse.jdt.internal.junit.launcher.JUnit5TestFinder.findTestsInContainer(JUnit5TestFinder.java:221)
at com.microsoft.java.test.plugin.searcher.JUnit5TestSearcher.findTestItemsInContainer(JUnit5TestSearcher.java:130)
at com.microsoft.java.test.plugin.util.TestSearchUtils.findTestPackagesAndTypes(TestSearchUtils.java:169)
Activity
[-]Searching tests cause freezes in big multi-modal projects with junit 5[/-][+]Searching tests cause freezes in big multi-module projects with junit 5[/+]github-actions commentedon Aug 22, 2026
Hi Oleg Agafonov (@JayDi85), I'm an AI Support assistant here to help with your issue. While the team reviews your request, I wanted to provide some possible tips and documentation that might help you in the meantime.
Suggestions
Scope test discovery to specific modules or folders:
mage-tests) in the Test Explorer and select Run All Tests, instead of running from the root workspace. This limits the search to that module’s test classes.Exclude large or irrelevant test packages via VS Code settings (in
.vscode/settings.json):{ "java.test.fileExcludes": [ "**/some-large-module/**" ] }Adjust the glob patterns to skip directories that don’t need to be scanned.
Track the underlying performance issue on the VS Code Java Test extension:
Other references with low confidence
Big java project freezes with problems auto-scanning (1 million lines of code)
VS Code Java extension freezes during background problem-scanning on the same
magefree/mageproject. Not specific to test discovery.Big java project freezes with problems auto-scanning (1 million lines of code) redhat-developer/vscode-java#867
Multiple selections in test UI run individually/isolated
Discusses slowdown when selecting multiple tests due to repeated setup/teardown cycles, but not global test search.
Multiple selections in test UI run individually/isolated #1836
The team will respond to your issue shortly. I hope these suggestions are helpful in the meantime. If this comment helped you, please give it a 👍. If the suggestion was not helpful or incorrect, please give it a 👎. Your feedback helps us improve!
wenytang-ms commentedon Aug 24, 2026
Thanks for the detailed report and the public reproduction project.
I was able to reproduce the prolonged project-level "Searching tests..." behavior and reviewed the supplied thread dumps. The sampled threads are
RUNNABLEand repeatedly show work underJUnit5TestFinder.internalIsTest()and binding-resolved AST creation, so the dumps do not show a deadlock. However, the complete "Searching tests..." phase also includes additional work in vscode-java-test, so the entire delay should not be attributed toJUnit5TestFinderbased on the current data.There are also potential improvement areas in vscode-java-test's current discovery flow:
These extension-side behaviors are particularly relevant when comparing initial and repeated project-level runs. This issue is an appropriate place to continue investigating that part of the discovery flow.
For the JDT/JUnit discovery path observed in the thread dumps, I opened eclipse-jdtls/eclipse.jdt.ls#3870 with the pinned reproduction revision and the corresponding code observations. The server-side invocation originates from vscode-java-test through:
That issue focuses on the cost observed during a single JUnit 5 finder invocation and on determining the appropriate layer for any finder-level change. The repeated project resolution and subsequent method-level expansion remain specific to vscode-java-test and are tracked here.
One correction to the automated suggestion above:
java.test.fileExcludesis not a supported Test Runner for Java setting, so that workaround should be disregarded.wenytang-ms commentedon Sep 21, 2026
Thanks again for the detailed report and the public reproduction project.
The vscode-java-test part of this issue has been addressed by #1916. Resolved Project and Class test items are now reused, concurrent resolutions are coalesced, and the cached state is invalidated when a refresh or classpath change requires discovery to run again. In the
magefree/magevalidation, an already-resolved project expanded in about 2.4 seconds instead of repeating the roughly 163-second discovery.The remaining cost is the initial JUnit 5 discovery performed in JDT/JDT LS. That belongs to the JDT scope and is tracked separately in eclipse-jdtls/eclipse.jdt.ls#3870.
Closing this issue as completed for the vscode-java-test scope.