This commit is contained in:
Florian THIERRY
2021-04-30 15:44:28 +02:00
commit df3b76f166
27 changed files with 1052 additions and 0 deletions

View File

@@ -0,0 +1,85 @@
package com.ippon.trainning.kafkaintegrationtest.kafkaconsumer.consumer;
import com.ippon.trainning.kafkaintegrationtest.kafkacommontest.extension.EmbeddedKafkaExtension;
import com.ippon.trainning.kafkaintegrationtest.kafkaconsumer.service.MessageService;
import org.apache.kafka.common.serialization.StringSerializer;
import org.awaitility.Durations;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Bean;
import org.springframework.kafka.core.DefaultKafkaProducerFactory;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.core.ProducerFactory;
import org.springframework.kafka.test.context.EmbeddedKafka;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.util.Map;
import java.util.UUID;
import static org.apache.kafka.clients.producer.ProducerConfig.*;
import static org.awaitility.Awaitility.await;
import static org.mockito.BDDMockito.then;
@ExtendWith({
SpringExtension.class,
MockitoExtension.class,
EmbeddedKafkaExtension.class
})
@SpringBootTest(classes = {
KafkaConsumerIT.KafkaConsumerITConfiguration.class
}, properties = "spring.kafka.bootstrap-servers=${spring.embedded.kafka.brokers}")
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@EmbeddedKafka
@ActiveProfiles({"test"})
public class KafkaConsumerIT {
@TestConfiguration
public static class KafkaConsumerITConfiguration {
@Bean
public DefaultKafkaProducerFactory<String, String> producerFactory(
@Value("${server.kafka.bootstrapAddress}") String bootstrapAddress
) {
Map<String, Object> configProperties = Map.of(
BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress,
KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class,
VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class
);
return new DefaultKafkaProducerFactory<>(configProperties);
}
@Bean
public KafkaTemplate<String, String> kafkaTemplate(ProducerFactory<String, String> producerFactory) {
return new KafkaTemplate<>(producerFactory);
}
}
@Autowired
private KafkaTemplate<String, String> kafkaTemplate;
@Value("${server.kafka.topic}")
private String topic;
@MockBean
private MessageService messageService;
@Test
void should_comsume_a_message_from_kafka_topic() {
// given
String key = UUID.randomUUID().toString();
String message = "A message to consume";
// when
kafkaTemplate.send(topic, key, message);
// then
await().atMost(Durations.FIVE_SECONDS).untilAsserted(() -> then(messageService).should().handleMessage(key, message));
}
}

View File

@@ -0,0 +1,5 @@
server:
kafka:
bootstrapAddress: "${spring.embedded.kafka.brokers:}"
topic: topic-test
groupId: groupId-test

View File

@@ -0,0 +1,11 @@
package com.ippon.trainning.kafkaintegrationtest.kafkaconsumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class KafkaConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(KafkaConsumerApplication.class, args);
}
}

View File

@@ -0,0 +1,46 @@
package com.ippon.trainning.kafkaintegrationtest.kafkaconsumer.config;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
import org.springframework.kafka.core.ConsumerFactory;
import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
import java.util.Map;
import static org.apache.kafka.clients.CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG;
import static org.apache.kafka.clients.CommonClientConfigs.GROUP_ID_CONFIG;
import static org.apache.kafka.clients.consumer.ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG;
import static org.apache.kafka.clients.consumer.ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG;
@Configuration
public class KafkaConsumerConfiguration {
private final String bootstrapAddress;
private final String groupId;
public KafkaConsumerConfiguration(@Value("${server.kafka.bootstrapAddress}") String bootstrapAddress,
@Value("${server.kafka.groupId}") String groupId) {
this.bootstrapAddress = bootstrapAddress;
this.groupId = groupId;
}
@Bean
public ConsumerFactory<String, String> consumerFactory() {
Map<String, Object> props = Map.of(
BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress,
VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class,
KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class,
GROUP_ID_CONFIG, groupId
);
return new DefaultKafkaConsumerFactory<>(props);
}
@Bean
public ConcurrentKafkaListenerContainerFactory<String, String> containerFactory(ConsumerFactory<String, String> consumerFactory) {
ConcurrentKafkaListenerContainerFactory<String, String> factory = new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory);
return factory;
}
}

View File

@@ -0,0 +1,25 @@
package com.ippon.trainning.kafkaintegrationtest.kafkaconsumer.consumer;
import com.ippon.trainning.kafkaintegrationtest.kafkaconsumer.service.MessageService;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class KafkaConsumer {
private final MessageService messageService;
public KafkaConsumer(MessageService messageService) {
this.messageService = messageService;
}
@KafkaListener(
containerFactory = "containerFactory",
topics = "${server.kafka.topic}"
)
public void listenTopic(ConsumerRecord<String, String> record) {
messageService.handleMessage(record.key(), record.value());
}
}

View File

@@ -0,0 +1,12 @@
package com.ippon.trainning.kafkaintegrationtest.kafkaconsumer.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class MessageService {
public void handleMessage(String key, String message) {
log.info("Message consumed: <{}> - <{}>", key, message);
}
}

View File

@@ -0,0 +1,6 @@
server:
port: 8081
kafka:
bootstrapAddress: localhost:9092
topic: topic-test
groupId: groupId-test

View File

@@ -0,0 +1,13 @@
package com.ippon.trainning.kafkaintegrationtest.kafkaconsumer;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class KafkaConsumerApplicationTests {
@Test
void contextLoads() {
}
}