microsoft / microsoft/vscode-java-test

Searching tests cause freezes in big multi-module projects with junit 5

Open
#1,915 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

ai-triaged bug high-priority investigating junit maven test-discovery
Dominant language
TypeScript
Stars
340
Forks
173
Avg merge
1d 19h
Merged PRs (30d)
18

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)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the delay with the linked mage project and the described test-search command. Start at JUnit5TestSearcher.findTestItemsInContainer and TestSearchUtils.findTestPackagesAndTypes, then inspect the JUnit5TestFinder.internalIsTest path alongside the provided dumps. Done means root-module test discovery no longer freezes for minutes while single-test and small-folder discovery continue to work.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, typescript
Domain
performance, testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.