Skip to content

Conversation

holly-cummins
Copy link
Contributor

Resolves #48295.

I don't love this fix, but I can't think of a better option. The problem happens because the Eclipse launcher starts a launcher session twice, once with SessionPerRequestLauncher.discover and once with SessionPerRequestLauncher.execute. The second one starts after discovery finished, so there's nothing to set the TCCL back to the app classloader.

The problem wouldn't happen if we didn't set a TCCL when launcher sessions are opened, but that has to be done to support gradle.

These are the paths of the first and second call.

First

	io.quarkus.test.junit.launcher.CustomLauncherInterceptor.launcherSessionOpened(CustomLauncherInterceptor.java:27)
	at org.junit.platform.launcher.listeners.session.CompositeLauncherSessionListener.lambda$launcherSessionOpened$0(CompositeLauncherSessionListener.java:36)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at java.base/java.util.Collections$UnmodifiableCollection.forEach(Collections.java:1092)
	at org.junit.platform.launcher.listeners.session.CompositeLauncherSessionListener.launcherSessionOpened(CompositeLauncherSessionListener.java:36)
	at org.junit.platform.launcher.core.DefaultLauncherSession.<init>(DefaultLauncherSession.java:60)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.createSession(SessionPerRequestLauncher.java:75)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.discover(SessionPerRequestLauncher.java:55)
	at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.<init>(JUnit5TestReference.java:47)
	at org.eclipse.jdt.internal.junit5.runner.JUnit5TestLoader.createUnfilteredTest(JUnit5TestLoader.java:88)
	at org.eclipse.jdt.internal.junit5.runner.JUnit5TestLoader.createTest(JUnit5TestLoader.java:69)
	at org.eclipse.jdt.internal.junit5.runner.JUnit5TestLoader.loadTests(JUnit5TestLoader.java:56)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:504)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:748)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:443)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:211)

Second

 io.quarkus.test.junit.launcher.CustomLauncherInterceptor.launcherSessionOpened(CustomLauncherInterceptor.java:27)
	at org.junit.platform.launcher.listeners.session.CompositeLauncherSessionListener.lambda$launcherSessionOpened$0(CompositeLauncherSessionListener.java:36)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at java.base/java.util.Collections$UnmodifiableCollection.forEach(Collections.java:1092)
	at org.junit.platform.launcher.listeners.session.CompositeLauncherSessionListener.launcherSessionOpened(CompositeLauncherSessionListener.java:36)
	at org.junit.platform.launcher.core.DefaultLauncherSession.<init>(DefaultLauncherSession.java:60)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.createSession(SessionPerRequestLauncher.java:75)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:69)
	at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:100)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:520)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:748)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:443)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:211)

For comparison, running in IntelliJ, the stack is (so we can't even make a decision based on SessionPerRequestLauncher.execute being in the stack).

java.lang.Exception: who called me
	at io.quarkus.test.junit.launcher.CustomLauncherInterceptor.launcherSessionOpened(CustomLauncherInterceptor.java:27)
	at org.junit.platform.launcher.listeners.session.CompositeLauncherSessionListener.lambda$launcherSessionOpened$0(CompositeLauncherSessionListener.java:36)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at java.base/java.util.Collections$UnmodifiableCollection.forEach(Collections.java:1092)
	at org.junit.platform.launcher.listeners.session.CompositeLauncherSessionListener.launcherSessionOpened(CompositeLauncherSessionListener.java:36)
	at org.junit.platform.launcher.core.DefaultLauncherSession.<init>(DefaultLauncherSession.java:60)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.createSession(SessionPerRequestLauncher.java:75)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:62)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:231)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)

Copy link

quarkus-bot bot commented Jun 9, 2025

Status for workflow Quarkus CI

This is the status report for running Quarkus CI on commit 514a5f9.

✅ The latest workflow run for the pull request has completed successfully.

It should be safe to merge provided you have a look at the other checks in the summary.

You can consult the Develocity build scans.


Flaky tests - Develocity

⚙️ JVM Tests - JDK 17 Windows

📦 extensions/micrometer-opentelemetry/deployment

io.quarkus.micrometer.opentelemetry.deployment.compatibility.MicrometerTimedInterceptorTest.testTimeMethod_Failed - History

  • Stream has no elements - java.lang.IllegalArgumentException
java.lang.IllegalArgumentException: Stream has no elements
	at io.quarkus.micrometer.opentelemetry.deployment.common.MetricDataFilter.lastReadingDataPoint(MetricDataFilter.java:236)
	at io.quarkus.micrometer.opentelemetry.deployment.compatibility.MicrometerTimedInterceptorTest.testTimeMethod_Failed(MicrometerTimedInterceptorTest.java:100)
	at java.base/java.lang.reflect.Method.invoke(Method.java:569)
	at io.quarkus.test.QuarkusUnitTest.runExtensionMethod(QuarkusUnitTest.java:521)
	at io.quarkus.test.QuarkusUnitTest.interceptTestMethod(QuarkusUnitTest.java:435)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)

⚙️ JVM Integration Tests - JDK 17

📦 integration-tests/opentelemetry

io.quarkus.it.opentelemetry.LoggingResourceTest.testException - History

  • Condition with Lambda expression in io.quarkus.it.opentelemetry.LoggingResourceTest was not fulfilled within 2 minutes. - org.awaitility.core.ConditionTimeoutException
org.awaitility.core.ConditionTimeoutException: Condition with Lambda expression in io.quarkus.it.opentelemetry.LoggingResourceTest was not fulfilled within 2 minutes.
	at org.awaitility.core.ConditionAwaiter.await(ConditionAwaiter.java:167)
	at org.awaitility.core.CallableCondition.await(CallableCondition.java:78)
	at org.awaitility.core.CallableCondition.await(CallableCondition.java:26)
	at org.awaitility.core.ConditionFactory.until(ConditionFactory.java:1160)
	at org.awaitility.core.ConditionFactory.until(ConditionFactory.java:1129)
	at io.quarkus.it.opentelemetry.LoggingResourceTest.testException(LoggingResourceTest.java:113)
	at java.base/java.lang.reflect.Method.invoke(Method.java:569)

⚙️ JVM Integration Tests - JDK 21

📦 integration-tests/opentelemetry

io.quarkus.it.opentelemetry.LoggingResourceTest.testException - History

  • Condition with Lambda expression in io.quarkus.it.opentelemetry.LoggingResourceTest was not fulfilled within 2 minutes. - org.awaitility.core.ConditionTimeoutException
org.awaitility.core.ConditionTimeoutException: Condition with Lambda expression in io.quarkus.it.opentelemetry.LoggingResourceTest was not fulfilled within 2 minutes.
	at org.awaitility.core.ConditionAwaiter.await(ConditionAwaiter.java:167)
	at org.awaitility.core.CallableCondition.await(CallableCondition.java:78)
	at org.awaitility.core.CallableCondition.await(CallableCondition.java:26)
	at org.awaitility.core.ConditionFactory.until(ConditionFactory.java:1160)
	at org.awaitility.core.ConditionFactory.until(ConditionFactory.java:1129)
	at io.quarkus.it.opentelemetry.LoggingResourceTest.testException(LoggingResourceTest.java:113)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)

@geoand
Copy link
Contributor

geoand commented Jun 10, 2025

Another horrible hack would be to decide based on the contents of the stack, but I believe what you've done is better.

@gsmet
Copy link
Member

gsmet commented Jun 10, 2025

The problem wouldn't happen if we didn't set a TCCL when launcher sessions are opened, but that has to be done to support gradle.

Wouldn't there be a way to detect Gradle instead and only install this hack if Gradle? Maybe a system property or env var set by Gradle?

@holly-cummins
Copy link
Contributor Author

holly-cummins commented Jun 10, 2025

The problem wouldn't happen if we didn't set a TCCL when launcher sessions are opened, but that has to be done to support gradle.

Wouldn't there be a way to detect Gradle instead and only install this hack if Gradle? Maybe a system property or env var set by Gradle?

That was my original idea, too. Detecting gradle is pretty easy, but there's two problems with having an 'is this gradle?' guard on the TCCL-setting-in-session-opened:

  • Setting the TCCL when the launcher session is opened affects a whole bunch of things downstream. For example, in ConfigLauncherSession, the code has to do some extra work if a TCCL got set upstream. As it happens, the current implementation of ConfigLauncherSession tolerates both TCCL-set and not-TCCL-set cases, but earlier versions definitely didn't. And I suspect there are some other bits of code where the implementation varies depending on what happened when the launcher session was opened. Which leads us to ...
  • Coverage. We have a lot of different ways tests can be run (continuous testing, normal, mixed with plain tests, nested tests, multi-module, instrumented with meta-inf services, etc). Only some of those are exercised in the gradle tests. If we have a different behaviour for the TCCL on the gradle path, I'm worried we'll miss coverage of some of the 'gradle + exotic scenario' paths. Normally that might not matter too much, but I am discovering that small differences in exactly when the TCCL gets set can break things.

What I would love is a gradle-specific pre-load hook, but I can't find any evidence of one. :(

@holly-cummins
Copy link
Contributor Author

Another horrible hack would be to decide based on the contents of the stack, but I believe what you've done is better.

We couldn't do stack on its own because the 'unwanted' Eclipse stack is most similar to the 'good' IntelliJ stack (grrr), but thinking about it more, we could use the stack to distinguish between the 'wanted' and 'unwanted' Eclipse stacks. If the static variable causes problems, we could reconsider it. I was a bit nervous about how the static would interfere with things like maven surefire re-running, but decided it was ok as long as I only used it in an Eclipse single-run context.

@geoand
Copy link
Contributor

geoand commented Jun 10, 2025

we could use the stack to distinguish between the 'wanted' and 'unwanted' Eclipse stacks.

Exactly

@gsmet
Copy link
Member

gsmet commented Jun 11, 2025

So should this get in or do we need another patch?

@holly-cummins
Copy link
Contributor Author

So should this get in or do we need another patch?

It should go in. It was just waiting for someone to merge it, so I'll do that now.

@holly-cummins holly-cummins merged commit 97ada7c into quarkusio:main Jun 11, 2025
57 checks passed
@quarkus-bot quarkus-bot bot added this to the 3.24 - main milestone Jun 11, 2025
@holly-cummins holly-cummins deleted the tolerate-eclipse-for-integration-tests branch June 11, 2025 10:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unable to run QuarkusIntegrationTests in Eclipse since Quarkus 3.22

4 participants