GH-666: Single global embedded Kafka with JUnit 5 (#2308)
* GH-666: Single global embedded Kafka with JUnit 5 Fixes https://github.com/spring-projects/spring-kafka/issues/666 * Introduce a `GlobalEmbeddedKafkaTestExecutionListener` which is registered by the service loader from JUnit Platform * Make its activation conditional based on the `spring.kafka.global.embedded.enabled` system property * Expose some other configuration properties for the target global `EmbeddedKafkaBroker` * Verify its functionality via manual `Launcher.execute()` * Add more `@DirtiesContext` to some tests in the `spring-kafka-test` which don't close their embedded brokers on the exit * * Print local launcher summary into SOUT for tracing the nested problems * * Fix prefix for `file:` resource in the test * * Make `junit-platform-launcher` as provided dep - this is part of JUnit platform the test plan is going to be run * Add missed new line in the end of `junit-platform.properties` * Rethrow an exception from the local launcher in the `GlobalEmbeddedKafkaTestExecutionListenerTests` to fail if its suite test classes have failed. * * Fix JavaDocs for `GlobalEmbeddedKafkaTestExecutionListener` constants * Move system properties clean up in the `GlobalEmbeddedKafkaTestExecutionListenerTests` into `@AfterAll` * Add docs for this new feature * Add `sample-05` to demonstrate global embedded Kafka in action via Maven configuration * * Mention `sample-05` in the common `README.adoc` for samples * * Fix language in the `testing.adoc` * Add new lines into new files * Add `spring.kafka.consumer.auto-offset-reset=earliest` to make a consumer to start from the beginning of the partition: fixes a race condition when publishing happens before consumer is started * Make `mvnw` as an executable * Add `spring.embedded.kafka.brokers.property` explanation into docs * * Fix language in docs Co-authored-by: Gary Russell <grussell@vmware.com> * * Make `Sample05Application2Tests` passing * Remove `deliberately failing` sentence from the JavaDoc an README * Clean up unused imports Co-authored-by: Gary Russell <grussell@vmware.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.kafka.annotation.KafkaListener;
|
||||
|
||||
/**
|
||||
* Plain Kafka listener sample which purpose is only to be used in the tests assertions.
|
||||
* See unit tests for this project for more information.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class Sample05Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Sample05Application.class, args);
|
||||
}
|
||||
|
||||
@KafkaListener(id ="sampleListener", topics = "topic1")
|
||||
void listenForTopic(String payload) {
|
||||
System.out.println("Received: " + payload);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
spring.kafka.bootstrap-servers=${spring.embedded.kafka.brokers}
|
||||
spring.kafka.producer.properties[max.block.ms]=1000
|
||||
spring.kafka.consumer.auto-offset-reset=earliest
|
||||
logging.level.root=error
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.system.CapturedOutput;
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||
import org.springframework.kafka.core.KafkaTemplate;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
|
||||
/**
|
||||
* This test is going to fail from IDE since there is no exposed {@code spring.embedded.kafka.brokers} system property.
|
||||
* Use Maven to run tests which enables global embedded Kafka broker via properties provided to Surefire plugin.
|
||||
*/
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
@SpringBootTest
|
||||
@DirtiesContext
|
||||
class Sample05Application1Tests {
|
||||
|
||||
@Autowired
|
||||
KafkaTemplate<String, String> kafkaTemplate;
|
||||
|
||||
@Test
|
||||
void testKafkaListener(CapturedOutput output) {
|
||||
this.kafkaTemplate.send("topic1", "testData");
|
||||
|
||||
await().until(() -> output.getOut().contains("Received: testData"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.kafka.common.errors.TimeoutException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.kafka.KafkaException;
|
||||
import org.springframework.kafka.core.KafkaTemplate;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
|
||||
/**
|
||||
* This test is going to fail from IDE since there is no exposed {@code spring.embedded.kafka.brokers} system property.
|
||||
* This test demonstrates that global embedded Kafka broker config for {@code auto.create.topics.enable=false}
|
||||
* is in an effect - the topic {@code nonExistingTopic} does not exist on the broker.
|
||||
* See {@code /resources/kafka-broker.properties} and Maven Surefire plugin configuration.
|
||||
*/
|
||||
@SpringBootTest
|
||||
@DirtiesContext
|
||||
class Sample05Application2Tests {
|
||||
|
||||
@Autowired
|
||||
KafkaTemplate<String, String> kafkaTemplate;
|
||||
|
||||
@Test
|
||||
void testKafkaTemplateSend() {
|
||||
assertThatExceptionOfType(KafkaException.class)
|
||||
.isThrownBy(() ->
|
||||
this.kafkaTemplate.send("nonExistingTopic", "fake data").get(10, TimeUnit.SECONDS))
|
||||
.withRootCauseExactlyInstanceOf(TimeoutException.class)
|
||||
.withMessageContaining("Send failed")
|
||||
.withStackTraceContaining("Topic nonExistingTopic not present in metadata");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
spring.kafka.embedded.topics=topic1,topic2
|
||||
@@ -0,0 +1 @@
|
||||
auto.create.topics.enable=false
|
||||
26
samples/sample-05/src/test/resources/logback-test.xml
Normal file
26
samples/sample-05/src/test/resources/logback-test.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<!-- encoders are assigned the type
|
||||
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="org.springframework.kafka.test.junit" level="debug"/>
|
||||
<logger name="org.springframework.kafka.test" level="warn"/>
|
||||
<logger name="org.apache.kafka.clients" level="warn"/>
|
||||
<logger name="org.apache.kafka.clients.NetworkClient" level="error"/>
|
||||
<logger name="org.apache.kafka.common.network.Selector" level="error"/>
|
||||
<logger name="kafka.server.ReplicaFetcherThread" level="error"/>
|
||||
<logger name="kafka.server.LogDirFailureChannel" level="error"/>
|
||||
<logger name="kafka.server.BrokerMetadataCheckpoint" level="error"/>
|
||||
<logger name="kafka.utils.CoreUtils$" level="error"/>
|
||||
<logger name="org.apache.zookeeper.server.ZooKeeperServer" level="error"/>
|
||||
|
||||
<root level="error">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user