Skip to content

Disable Global Embedded Kafka Support if JUnit Platform is < 1.8 #2481

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

Closed
wilkinsona opened this issue Nov 16, 2022 · 10 comments · Fixed by #2482
Closed

Disable Global Embedded Kafka Support if JUnit Platform is < 1.8 #2481

wilkinsona opened this issue Nov 16, 2022 · 10 comments · Fixed by #2482
Assignees
Milestone

Comments

@wilkinsona
Copy link
Member

With thanks to @DennisBecker for reporting this on Gitter, GlobalEmbeddedKafkaTestExecutionListener requires junit-platform-launcher 1.8 or later. Surefire's default configuration doesn't meet this requirement which results in a failure when running ./mvnw test on an app that depends on spring-kafka-test:

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.749 s
[INFO] Finished at: 2022-11-16T13:03:13Z
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.2:test (default-test) on project springtest: There are test failures.
[ERROR] 
[ERROR] Please refer to /Users/awilkinson/Downloads/springtest/target/surefire-reports for the individual test results.
[ERROR] Please refer to dump files (if any exist) [date].dump, [date]-jvmRun[N].dump and [date].dumpstream.
[ERROR] There was an error in the forked process
[ERROR] 'org.junit.platform.engine.ConfigurationParameters org.junit.platform.launcher.TestPlan.getConfigurationParameters()'
[ERROR] org.apache.maven.surefire.booter.SurefireBooterForkException: There was an error in the forked process
[ERROR] 'org.junit.platform.engine.ConfigurationParameters org.junit.platform.launcher.TestPlan.getConfigurationParameters()'
[ERROR] 	at org.apache.maven.plugin.surefire.booterclient.ForkStarter.fork(ForkStarter.java:656)
[ERROR] 	at org.apache.maven.plugin.surefire.booterclient.ForkStarter.run(ForkStarter.java:282)
[ERROR] 	at org.apache.maven.plugin.surefire.booterclient.ForkStarter.run(ForkStarter.java:245)
[ERROR] 	at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeProvider(AbstractSurefireMojo.java:1183)
[ERROR] 	at org.apache.maven.plugin.surefire.AbstractSurefireMojo.executeAfterPreconditionsChecked(AbstractSurefireMojo.java:1011)
[ERROR] 	at org.apache.maven.plugin.surefire.AbstractSurefireMojo.execute(AbstractSurefireMojo.java:857)
[ERROR] 	at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:137)
[ERROR] 	at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute2(MojoExecutor.java:370)
[ERROR] 	at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute(MojoExecutor.java:351)
[ERROR] 	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:215)
[ERROR] 	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:171)
[ERROR] 	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:163)
[ERROR] 	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:117)
[ERROR] 	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:81)
[ERROR] 	at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:56)
[ERROR] 	at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
[ERROR] 	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:294)
[ERROR] 	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:192)
[ERROR] 	at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:105)
[ERROR] 	at org.apache.maven.cli.MavenCli.execute(MavenCli.java:960)
[ERROR] 	at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:293)
[ERROR] 	at org.apache.maven.cli.MavenCli.main(MavenCli.java:196)
[ERROR] 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[ERROR] 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
[ERROR] 	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[ERROR] 	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
[ERROR] 	at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:282)
[ERROR] 	at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:225)
[ERROR] 	at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:406)
[ERROR] 	at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:347)
[ERROR] 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[ERROR] 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
[ERROR] 	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[ERROR] 	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
[ERROR] 	at org.apache.maven.wrapper.BootstrapMainStarter.start(BootstrapMainStarter.java:47)
[ERROR] 	at org.apache.maven.wrapper.WrapperExecutor.execute(WrapperExecutor.java:156)
[ERROR] 	at org.apache.maven.wrapper.MavenWrapperMain.main(MavenWrapperMain.java:72)

The dump reveals the problem:

java.lang.NoSuchMethodError: 'org.junit.platform.engine.ConfigurationParameters org.junit.platform.launcher.TestPlan.getConfigurationParameters()'
        at org.springframework.kafka.test.junit.GlobalEmbeddedKafkaTestExecutionListener.testPlanExecutionStarted(GlobalEmbeddedKafkaTestExecutionListener.java:91)
        at org.junit.platform.launcher.core.TestExecutionListenerRegistry$CompositeTestExecutionListener.lambda$testPlanExecutionStarted$6(TestExecutionListenerRegistry.java:97)
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
        at org.junit.platform.launcher.core.TestExecutionListenerRegistry.notifyTestExecutionListeners(TestExecutionListenerRegistry.java:59)
        at org.junit.platform.launcher.core.TestExecutionListenerRegistry.access$100(TestExecutionListenerRegistry.java:28)
        at org.junit.platform.launcher.core.TestExecutionListenerRegistry$CompositeTestExecutionListener.testPlanExecutionStarted(TestExecutionListenerRegistry.java:97)
        at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:183)
        at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:202)
        at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:181)
        at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
        at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:150)
        at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:124)
        at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:384)
        at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:345)
        at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:126)
        at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:418)

Once the prerequisites have been documented, we can figure out if there's anything we could/should do in Spring Boot or on start.spring.io to set things up automatically.

@artembilan
Copy link
Member

The maven-surefire-plugin does not bring the latest junit-platform-launcher.
Must be 3.0.0-M7.
That testPlan.getConfigurationParameters() is @API(status = MAINTAINED, since = "1.8").
And looks like a default maven-surefire-plugin brings for us 1.7.

I wonder why JUnit does not document this by itself: https://junit.org/junit5/docs/current/user-guide/#running-tests-build-maven-config-params.

This is really has nothing to do with Spring for Apache Kafka - just out of scope.

/CC @sbrannen

@wilkinsona
Copy link
Member Author

Must be 3.0.0-M7

I don't think we can require a milestone of Surefire. For this reason, Boot's starter parent uses 2.22.2 by default.

This is really has nothing to do with Spring for Apache Kafka - just out of scope

This is probably obvious given that I opened the issue here, but I don't agree with this. Spring Kafka requiring 1.8 of the launcher is fairly aggressive and, as the failure above shows, it doesn't work out of the box using the latest non-milestone release of Maven's testing support. It may also fail in an IDE depending on how up-to-date its JUnit Platform integration is. IMO, it's really up to Spring Kafka to document how users can configure their build and/or IDE to meet its requirements or for those requirement to be lowered so that they're met by default.

@artembilan
Copy link
Member

Sure! I can see what we can do to disable this listener if launcher is not version 1.8, but really would like to hear from JUnit team what do they think...

@sbrannen
Copy link
Member

The Maven documentation in the JUnit 5 User Guide is outdated and can be improved; however, the linked sample project uses Surefire 3.0 M6.

The linked Surefire documentation also uses Surefire 3.0 M7 and explains a bit about mismatched versions.

For the GraalVM Native Build Tools, I added a dedicated section explaining this as well.

So you might want to include information similar to that in the Spring Kafka documentation.

As a side note, the JUnit 5 User Guide does actually provide similar guidance in the IntelliJ section, but it's not apparent that one should do that for Maven Surefire versions older than 3.0 M4.

@sbrannen
Copy link
Member

I've created junit-team/junit5#3093 to improve the documentation in the JUnit 5 User Guide.

@garyrussell
Copy link
Contributor

I think we can just use reflection to detect the presence of that method and just exit testPlanExecutionStarted() if it's not.

@wilkinsona
Copy link
Member Author

I think we can just use reflection to detect the presence of that method

That sounds good to me. If you go down this route, please also add a reflection hint for it so that it'll work in native tests too.

@garyrussell garyrussell self-assigned this Nov 16, 2022
@garyrussell garyrussell added this to the 3.0.0 milestone Nov 16, 2022
@artembilan
Copy link
Member

I think something like:

public static final boolean JUNIT_PLATFORM_18_PRESENT =
			ClassUtils.isPresent("org.junit.platform.launcher.listeners.UniqueIdTrackingListener", null);

is enough for both both Maven Surefire 2.22.2 and native.
I know there is some trick in Spring AOT to evaluate this kind of constants.

@garyrussell
Copy link
Contributor

That's marked as experimental; I'd rather use something that won't go away.

@artembilan
Copy link
Member

OK. So, let's watch for that TestPlan.getConfigurationParameters() then!

garyrussell added a commit to garyrussell/spring-kafka that referenced this issue Nov 16, 2022
Resolves spring-projects#2481

The Maven Surefire plugin uses an older version of JUnit platform
which is incompatible with the Global embedded broker.

Check that the platform version is compatible before attempting
to determine if a global embedded broker should be created.
garyrussell added a commit to garyrussell/spring-kafka that referenced this issue Nov 16, 2022
Resolves spring-projects#2481

The Maven Surefire plugin uses an older version of JUnit platform
which is incompatible with the Global embedded broker.

Check that the platform version is compatible before attempting
to determine if a global embedded broker should be created.

Tested with a Spring Boot application.
artembilan pushed a commit that referenced this issue Nov 16, 2022
Resolves #2481

The Maven Surefire plugin uses an older version of JUnit platform
which is incompatible with the Global embedded broker.

Check that the platform version is compatible before attempting
to determine if a global embedded broker should be created.

Tested with a Spring Boot application.

* Add doc comment.

* Add author.
@garyrussell garyrussell changed the title Document prerequisites for spring-kafka-test and how to configure them Disable Global Embedded Kafka Support if JUnit Platform is < 1.8 Nov 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants