Full compileTestJava run when only one test class changed

Hej,

I am using Gradle 6.5.1 on a single java project.

A clean compilation of the test folder for this project takes about 8 minutes.
If I change a single test class that is not used by other test classes Gradle starts compiling again the whole test folder and it takes again 8 minutes.

My expectation is that Gradle would only need to compile this file and not the whole folder.

I tried compiling with and without build-cache and I don’t see any difference in the behaviour.
All the previous tasks are marked as up-to-date by Gradle.

Here is the info output of Gradle.

....
Task :classes UP-TO-DATE
Skipping task ':classes' as it has no actions.
:classes (Thread[Execution worker for ':',5,main]) completed. Took 0.0 secs.
:compileTestJava (Thread[Execution worker for ':',5,main]) started.

Task :compileTestJava
Cache entries evicted. In-memory cache of ....gradle/caches/journal-1/file-access.bin: Size{400} MaxSize{400}, CacheStats{hitCount=0, missCount=0, loadSuccessCount=0, loadExceptionCount=0, totalLoadTime=0, evictionCount=521}
Performance may suffer from in-memory cache misses. Increase max heap size of Gradle build process to reduce cache misses.
Excluding []
Excluding []
Custom actions are attached to task ':compileTestJava'.
Build cache key for task ':compileTestJava' is c5d9263873a9750b37aef521e4d0b615
Task ':compileTestJava' is not up-to-date because:
  Input property 'stableSources' file <the class name of the changed file>.java has changed.
Created classpath snapshot for incremental compilation in 0.015 secs. 640 duplicate classes found in classpath (see all with --debug).
Class dependency analysis for incremental compilation took 0.03 secs.
Compiling with JDK Java compiler API.

There is this line Performance may suffer from in-memory cache... and I tried to compile with GRADLE_OPTS=-Xmx1G and GRADLE_OPTS=-Xmx512m. I also checked that the daemons have applied the memory settings via ps ax | grep gradle. But it makes no difference and the same message was coming up with these settings. It always says MaxSize{400}.

  • Is my expectation right that the change to this one file only would not need a full recompile of the test folder?
  • Is this message about max heap changing relevant and how can I avoid his message?
  • How can I speed up the compile time for one changed test class?
    Because in a scenario where I would like to run certain tests on a change with -t it takes now 8 minutes after every change.

Thanks for any help in advance.

Update:

In the debug out I found this message:
Full recompilation is required because the chosen compiler did not support incremental annotation processing
We use Lombok in version 1.18.12 which should support incremental compilation according to the docs.
Is this message about Lombok or the java compiler?

Update 2:
But the message from above is not consistent. After another change to the same file, I could not get the message from my first update. But I get

[org.gradle.api.internal.tasks.compile.incremental.SelectiveCompiler] Incremental compilation of 2 classes completed in 6 mins 38.689 secs.
[org.gradle.api.internal.tasks.compile.incremental.SelectiveCompiler] Recompiled classes [<class 1>, <class 2>]

And it seems it will incremental compile but takes again so long as it would compile the full test source folder.

1 Like

I cannot answer your question about the classes being recompiled, but the daemon is not controlled by GRADLE_OPTS, it is controlled by the org.gradle.jvmargs project property.
https://docs.gradle.org/current/userguide/build_environment.html#sec:configuring_jvm_memory

Thanks for pointing this out. Setting the memory with it removes the messages about the in-memory cache misses. But does not solve the avoidance of the full compile.

Update 3:

It looks like this is an issue with Gradle 6.5.1. I can not reproduce it with version 6.4.1.
I created a simple test project https://github.com/mschaaf/gradle-no-incremental-compile-issue

  1. run at least two times ./gradlew compileTestJava -i
  2. open file src/test/java/com/example/demo/DemoApplicationTests.java
  3. remove one System.out line
  4. re-run ./gradlew compileTestJava -i and you get Full recompilation is required because the chosen compiler did not support incremental annotation processing
  5. open the test file again
  6. add a line e.g. 3 times the system.out line
  7. re-run ./gradlew compileTestJava -i and you get Created classpath snapshot for incremental compilation in 0.001 secs. 1 duplicate classes found in classpath (see all with --debug). Class dependency analysis for incremental compilation took 0.0 secs. and not the message that a full recompilation is required

A few items…

This project is more difficult than necessary to run. The gradlew scripts are provided, but the gradle/wrapper/ contents that are required for using gradlew were not committed. Generating the needed wrapper files or using an installed distribution was required.

I don’t think the reproduction steps here are deterministic between environments. I can see cases where the Full recompilation is required because the chosen compiler did not support incremental annotation processing is shown, but for me, it is never as a result of step 4. Step 4 always gives me the same output as your step 7.

Probably the same issue as https://github.com/gradle/gradle/issues/13681, and not actually related to TestKit at all. Just noticed by that user when running TestKit.

@jjustinic I added the wrapper to the project.

The steps reproduce it always on my system Linux Ubuntu 20.04 kernel 5.4.0-40-generic

But the key problem here is that independent of the message the compilation takes as long as a full recompilation. You don’t recognize it on the test project because it is to small.

Semantics maybe, but I disagree. The key problem here is that logic in the incremental compilation feature had a bug introduced with recent changes. The symptom is far worse on a larger project, but the logging shows that the logic is broken, even on a small build. The size of the project doesn’t matter at all to recognize the bug itself, and it’s easier to test with a smaller project.

My main point was to call out that the problem may not be reproduced by everyone using the same steps. I can also reproduce it always on my system, but using different steps. As such, it is important for someone to find out what steps recreate it for them, and not stop and consider it fixed if it works for them on step 4.

@jjustinic My comments are not meant to offend and I don’t feel offended by yours. I recognize that you want to help to pin down the issue. I want to get it fixed too and I always appreciate the help in this forum.

I still have some questions:

  1. Is this now a confirmed bug?
  2. What is the priority of this issue?
  3. Do I need to open a separate issue on Github or is the issue you mentioned taken to track it?
  4. If not can you please link the issue that is used to track it officially?

Thanks for your help.

No concerns here. I expect we’re here to have a discussion more than anything else if we’re coming to the community forum rather than the issue tracker.

From the issue, we can see that a core dev looked at it, identified a change that likely caused the regression, and tagged a core dev from the correct team. That suggests that things are progressing, but I have no idea if more investigation has occurred or what internal discussions may have happened other than what’s commented publicly on that issue.

I believe that #13681 is a report of the same issue, provides good data for investigation, and that getting more attention to that issue will result in quicker resolution than starting over with a new issue that might be considered a duplicate. However, if you think you can do a better job of describing the issue and impact with your own issue vs. piling on to that one, no complaints here.

@jjustinic I will mark your last comment as the resolution and will follow the linked issue https://github.com/gradle/gradle/issues/13681

Thanks again for your help.