/* * Copyright 2012-2017 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 * * http://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 org.springframework.boot.autoconfigure.kafka; import java.io.File; import java.util.Collections; import java.util.Map; import javax.security.auth.login.AppConfigurationEntry; import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.common.config.SslConfigs; import org.apache.kafka.common.serialization.IntegerDeserializer; import org.apache.kafka.common.serialization.IntegerSerializer; import org.apache.kafka.common.serialization.LongDeserializer; import org.apache.kafka.common.serialization.LongSerializer; import org.junit.After; import org.junit.Test; import org.springframework.beans.DirectFieldAccessor; import org.springframework.boot.test.util.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.kafka.config.KafkaListenerContainerFactory; import org.springframework.kafka.core.DefaultKafkaConsumerFactory; import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.kafka.listener.AbstractMessageListenerContainer.AckMode; import org.springframework.kafka.security.jaas.KafkaJaasLoginModuleInitializer; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; /** * Tests for {@link KafkaAutoConfiguration}. * * @author Gary Russell * @author Stephane Nicoll */ public class KafkaAutoConfigurationTests { private AnnotationConfigApplicationContext context; @After public void closeContext() { if (this.context != null) { this.context.close(); } } @Test public void consumerProperties() { load("spring.kafka.bootstrap-servers=foo:1234", "spring.kafka.properties.foo=bar", "spring.kafka.properties.baz=qux", "spring.kafka.properties.foo.bar.baz=qux.fiz.buz", "spring.kafka.ssl.key-password=p1", "spring.kafka.ssl.keystore-location=classpath:ksLoc", "spring.kafka.ssl.keystore-password=p2", "spring.kafka.ssl.truststore-location=classpath:tsLoc", "spring.kafka.ssl.truststore-password=p3", "spring.kafka.consumer.auto-commit-interval=123", "spring.kafka.consumer.max-poll-records=42", "spring.kafka.consumer.auto-offset-reset=earliest", "spring.kafka.consumer.client-id=ccid", // test override common "spring.kafka.consumer.enable-auto-commit=false", "spring.kafka.consumer.fetch-max-wait=456", "spring.kafka.consumer.fetch-min-size=789", "spring.kafka.consumer.group-id=bar", "spring.kafka.consumer.heartbeat-interval=234", "spring.kafka.consumer.key-deserializer = org.apache.kafka.common.serialization.LongDeserializer", "spring.kafka.consumer.value-deserializer = org.apache.kafka.common.serialization.IntegerDeserializer"); DefaultKafkaConsumerFactory<?, ?> consumerFactory = this.context .getBean(DefaultKafkaConsumerFactory.class); @SuppressWarnings("unchecked") Map<String, Object> configs = (Map<String, Object>) new DirectFieldAccessor( consumerFactory).getPropertyValue("configs"); // common assertThat(configs.get(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG)) .isEqualTo(Collections.singletonList("foo:1234")); assertThat(configs.get(SslConfigs.SSL_KEY_PASSWORD_CONFIG)).isEqualTo("p1"); assertThat((String) configs.get(SslConfigs.SSL_KEYSTORE_LOCATION_CONFIG)) .endsWith(File.separator + "ksLoc"); assertThat(configs.get(SslConfigs.SSL_KEYSTORE_PASSWORD_CONFIG)).isEqualTo("p2"); assertThat((String) configs.get(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG)) .endsWith(File.separator + "tsLoc"); assertThat(configs.get(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG)) .isEqualTo("p3"); // consumer assertThat(configs.get(ConsumerConfig.CLIENT_ID_CONFIG)).isEqualTo("ccid"); // override assertThat(configs.get(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG)) .isEqualTo(Boolean.FALSE); assertThat(configs.get(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG)) .isEqualTo(123); assertThat(configs.get(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG)) .isEqualTo("earliest"); assertThat(configs.get(ConsumerConfig.FETCH_MAX_WAIT_MS_CONFIG)).isEqualTo(456); assertThat(configs.get(ConsumerConfig.FETCH_MIN_BYTES_CONFIG)).isEqualTo(789); assertThat(configs.get(ConsumerConfig.GROUP_ID_CONFIG)).isEqualTo("bar"); assertThat(configs.get(ConsumerConfig.HEARTBEAT_INTERVAL_MS_CONFIG)) .isEqualTo(234); assertThat(configs.get(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG)) .isEqualTo(LongDeserializer.class); assertThat(configs.get(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG)) .isEqualTo(IntegerDeserializer.class); assertThat(configs.get(ConsumerConfig.MAX_POLL_RECORDS_CONFIG)).isEqualTo(42); assertThat(configs.get("foo")).isEqualTo("bar"); assertThat(configs.get("baz")).isEqualTo("qux"); assertThat(configs.get("foo.bar.baz")).isEqualTo("qux.fiz.buz"); } @Test public void producerProperties() { load("spring.kafka.clientId=cid", "spring.kafka.producer.acks=all", "spring.kafka.producer.batch-size=20", "spring.kafka.producer.bootstrap-servers=bar:1234", // test override "spring.kafka.producer.buffer-memory=12345", "spring.kafka.producer.compression-type=gzip", "spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.LongSerializer", "spring.kafka.producer.retries=2", "spring.kafka.producer.ssl.key-password=p4", "spring.kafka.producer.ssl.keystore-location=classpath:ksLocP", "spring.kafka.producer.ssl.keystore-password=p5", "spring.kafka.producer.ssl.truststore-location=classpath:tsLocP", "spring.kafka.producer.ssl.truststore-password=p6", "spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.IntegerSerializer"); DefaultKafkaProducerFactory<?, ?> producerFactory = this.context .getBean(DefaultKafkaProducerFactory.class); @SuppressWarnings("unchecked") Map<String, Object> configs = (Map<String, Object>) new DirectFieldAccessor( producerFactory).getPropertyValue("configs"); // common assertThat(configs.get(ProducerConfig.CLIENT_ID_CONFIG)).isEqualTo("cid"); // producer assertThat(configs.get(ProducerConfig.ACKS_CONFIG)).isEqualTo("all"); assertThat(configs.get(ProducerConfig.BATCH_SIZE_CONFIG)).isEqualTo(20); assertThat(configs.get(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG)) .isEqualTo(Collections.singletonList("bar:1234")); // override assertThat(configs.get(ProducerConfig.BUFFER_MEMORY_CONFIG)).isEqualTo(12345L); assertThat(configs.get(ProducerConfig.COMPRESSION_TYPE_CONFIG)).isEqualTo("gzip"); assertThat(configs.get(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG)) .isEqualTo(LongSerializer.class); assertThat(configs.get(SslConfigs.SSL_KEY_PASSWORD_CONFIG)).isEqualTo("p4"); assertThat((String) configs.get(SslConfigs.SSL_KEYSTORE_LOCATION_CONFIG)) .endsWith(File.separator + "ksLocP"); assertThat(configs.get(SslConfigs.SSL_KEYSTORE_PASSWORD_CONFIG)).isEqualTo("p5"); assertThat((String) configs.get(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG)) .endsWith(File.separator + "tsLocP"); assertThat(configs.get(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG)) .isEqualTo("p6"); assertThat(configs.get(ProducerConfig.RETRIES_CONFIG)).isEqualTo(2); assertThat(configs.get(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG)) .isEqualTo(IntegerSerializer.class); assertThat(this.context.getBeansOfType(KafkaJaasLoginModuleInitializer.class)) .isEmpty(); } @Test public void listenerProperties() { load("spring.kafka.template.default-topic=testTopic", "spring.kafka.listener.ack-mode=MANUAL", "spring.kafka.listener.ack-count=123", "spring.kafka.listener.ack-time=456", "spring.kafka.listener.concurrency=3", "spring.kafka.listener.poll-timeout=2000", "spring.kafka.jaas.enabled=true", "spring.kafka.jaas.login-module=foo", "spring.kafka.jaas.control-flag=REQUISITE", "spring.kafka.jaas.options.useKeyTab=true"); DefaultKafkaProducerFactory<?, ?> producerFactory = this.context .getBean(DefaultKafkaProducerFactory.class); DefaultKafkaConsumerFactory<?, ?> consumerFactory = this.context .getBean(DefaultKafkaConsumerFactory.class); KafkaTemplate<?, ?> kafkaTemplate = this.context.getBean(KafkaTemplate.class); KafkaListenerContainerFactory<?> kafkaListenerContainerFactory = this.context .getBean(KafkaListenerContainerFactory.class); assertThat(new DirectFieldAccessor(kafkaTemplate) .getPropertyValue("producerFactory")).isEqualTo(producerFactory); assertThat(kafkaTemplate.getDefaultTopic()).isEqualTo("testTopic"); DirectFieldAccessor dfa = new DirectFieldAccessor(kafkaListenerContainerFactory); assertThat(dfa.getPropertyValue("consumerFactory")).isEqualTo(consumerFactory); assertThat(dfa.getPropertyValue("containerProperties.ackMode")) .isEqualTo(AckMode.MANUAL); assertThat(dfa.getPropertyValue("containerProperties.ackCount")).isEqualTo(123); assertThat(dfa.getPropertyValue("containerProperties.ackTime")).isEqualTo(456L); assertThat(dfa.getPropertyValue("concurrency")).isEqualTo(3); assertThat(dfa.getPropertyValue("containerProperties.pollTimeout")) .isEqualTo(2000L); assertThat(this.context.getBeansOfType(KafkaJaasLoginModuleInitializer.class)) .hasSize(1); KafkaJaasLoginModuleInitializer jaas = this.context.getBean( KafkaJaasLoginModuleInitializer.class); dfa = new DirectFieldAccessor(jaas); assertThat(dfa.getPropertyValue("loginModule")).isEqualTo("foo"); assertThat(dfa.getPropertyValue("controlFlag")) .isEqualTo(AppConfigurationEntry.LoginModuleControlFlag.REQUISITE); assertThat(((Map<String, String>) dfa.getPropertyValue("options"))) .containsExactly(entry("useKeyTab", "true")); } private void load(String... environment) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(KafkaAutoConfiguration.class); EnvironmentTestUtils.addEnvironment(ctx, environment); ctx.refresh(); this.context = ctx; } }