Skip to content

Commit be073a8

Browse files
garyrussellartembilan
authored andcommitted
GH-666: KafkaEmbedded doWithAdmin, addTopics
Resolves #666 Allow arbitrary `AdminClient` operations and adding topics. Polishing - PR Comments
1 parent 5fe9d5d commit be073a8

File tree

2 files changed

+84
-9
lines changed

2 files changed

+84
-9
lines changed

spring-kafka-test/src/main/java/org/springframework/kafka/test/rule/KafkaEmbedded.java

+36-9
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
import org.springframework.retry.support.RetryTemplate;
6060
import org.springframework.util.Assert;
6161

62+
import kafka.common.KafkaException;
6263
import kafka.server.KafkaConfig;
6364
import kafka.server.KafkaServer;
6465
import kafka.server.NotRunning;
@@ -234,19 +235,45 @@ public void before() throws Exception { //NOSONAR
234235
this.kafkaPorts[i] = TestUtils.boundPort(server, SecurityProtocol.PLAINTEXT);
235236
}
236237
}
237-
Map<String, Object> adminConfigs = new HashMap<>();
238-
adminConfigs.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, getBrokersAsString());
239-
AdminClient admin = AdminClient.create(adminConfigs);
240-
List<NewTopic> newTopics = Arrays.stream(this.topics)
241-
.map(t -> new NewTopic(t, this.partitionsPerTopic, (short) this.count))
242-
.collect(Collectors.toList());
243-
CreateTopicsResult createTopics = admin.createTopics(newTopics);
244-
createTopics.all().get();
245-
admin.close();
238+
addTopics(this.topics);
246239
System.setProperty(SPRING_EMBEDDED_KAFKA_BROKERS, getBrokersAsString());
247240
System.setProperty(SPRING_EMBEDDED_ZOOKEEPER_CONNECT, getZookeeperConnectionString());
248241
}
249242

243+
/**
244+
* Add topics to the existing broker(s) using the configured number of partitions.
245+
* @param topics the topics.
246+
* @since 2.1
247+
*/
248+
public void addTopics(String... topics) {
249+
doWithAdmin(admin -> {
250+
List<NewTopic> newTopics = Arrays.stream(topics)
251+
.map(t -> new NewTopic(t, this.partitionsPerTopic, (short) this.count))
252+
.collect(Collectors.toList());
253+
CreateTopicsResult createTopics = admin.createTopics(newTopics);
254+
try {
255+
createTopics.all().get();
256+
}
257+
catch (Exception e) {
258+
throw new KafkaException(e);
259+
}
260+
});
261+
}
262+
263+
/**
264+
* Create an {@link AdminClient} invoke the callback and reliable close the
265+
* admin.
266+
* @param callback the callback.
267+
* @since 2.1
268+
*/
269+
public void doWithAdmin(java.util.function.Consumer<AdminClient> callback) {
270+
Map<String, Object> adminConfigs = new HashMap<>();
271+
adminConfigs.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, getBrokersAsString());
272+
try (AdminClient admin = AdminClient.create(adminConfigs)) {
273+
callback.accept(admin);
274+
}
275+
}
276+
250277
public Properties createBrokerProperties(int i) {
251278
if (testUtilsCreateBrokerConfigMethod == null) {
252279
return TestUtils.createBrokerConfig(i, this.zkConnect, this.controlledShutdown,

src/reference/asciidoc/testing.adoc

+48
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,54 @@ Convenient constants `KafkaEmbedded.SPRING_EMBEDDED_KAFKA_BROKERS` and `KafkaEmb
102102
With the `KafkaEmbedded.brokerProperties(Map<String, String>)` you can provide additional properties for the Kafka server(s).
103103
See https://kafka.apache.org/documentation/#brokerconfigs[Kafka Config] for more information about possible broker properties.
104104

105+
106+
==== Using the Same Broker(s) for Multiple Test Classes
107+
108+
There is no built-in support for this, but it can be achieved with something similar to the following:
109+
110+
[source, java]
111+
----
112+
public final class KafkaEmbeddedHolder {
113+
114+
private static KafkaEmbedded kafkaEmbedded = new KafkaEmbedded(1, false);
115+
116+
private static boolean started;
117+
118+
public static KafkaEmbedded getKafkaEmbedded() {
119+
if (!started) {
120+
try {
121+
kafkaEmbedded.before();
122+
}
123+
catch (Exception e) {
124+
throw new KafkaException(e);
125+
}
126+
started = true;
127+
}
128+
return kafkaEmbedded;
129+
}
130+
131+
private KafkaEmbeddedHolder() {
132+
super();
133+
}
134+
135+
}
136+
----
137+
138+
And then, in each test class:
139+
140+
[source, java]
141+
----
142+
static {
143+
KafkaEmbeddedHolder.getKafkaEmbedded().addTopics(topic1, topic2);
144+
}
145+
146+
private static KafkaEmbedded embeddedKafka = KafkaEmbeddedHolder.getKafkaEmbedded();
147+
----
148+
149+
IMPORTANT: This example provides no mechanism for shutting down the broker(s) when all tests are complete.
150+
This could be a problem if, say, you run your tests in a gradle daemon.
151+
You should not use this technique in such a situation, or use something to call `destroy()` on the `KafkaEmbedded` when your tests are complete.
152+
105153
==== @EmbeddedKafka Annotation
106154
It is generally recommended to use the rule as a `@ClassRule` to avoid starting/stopping the broker between tests (and use a different topic for each test).
107155
Starting with _version 2.0_, if you are using Spring's test application context caching, you can also declare a `KafkaEmbedded` bean, so a single broker can be used across multiple test classes.

0 commit comments

Comments
 (0)