KafkaMessageListenerContainer.getAssignedPartitions returning 0 - spring

I am trying to run a test case with Kafka API with below test case code -
Taken from https://www.codenotfound.com/spring-kafka-consumer-producer-example.html
//SpringKafkaApplicationTest .java
import static org.assertj.core.api.Assertions.assertThat;
import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.kafka.config.KafkaListenerContainerFactory;
import org.springframework.kafka.config.KafkaListenerEndpoint;
import org.springframework.kafka.config.KafkaListenerEndpointRegistry;
import org.springframework.kafka.listener.MessageListenerContainer;
import org.springframework.kafka.test.rule.KafkaEmbedded;
import org.springframework.kafka.test.utils.ContainerTestUtils;
import org.springframework.test.context.junit4.SpringRunner;
//#TestExecutionListeners( { DependencyInjectionTestExecutionListener.class })
#RunWith(SpringRunner.class)
#SpringBootTest(classes= {SpringKafkaIntegrationApplication.class },webEnvironment = WebEnvironment.RANDOM_PORT)
public class SpringKafkaApplicationTest {
private static String BOOT_TOPIC = "boot.t";
#Autowired
private Sender sender;
#Autowired
private Receiver receiver;
#Autowired
private KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry;
#ClassRule
public static KafkaEmbedded embeddedKafka = new KafkaEmbedded(1, true, BOOT_TOPIC);
#Before
public void setUp() throws Exception {
// wait until the partitions are assigned
// kafkaListenerEndpointRegistry.registerListenerContainer(endpoint, factory);
for (MessageListenerContainer messageListenerContainer : kafkaListenerEndpointRegistry
.getListenerContainers()) {
**Below line gives issue**
ContainerTestUtils.waitForAssignment(messageListenerContainer,
embeddedKafka.getPartitionsPerTopic());
}
}
#Test
public void testReceive() throws Exception {
sender.send(BOOT_TOPIC, "Hello");
System.out.println("check");
receiver.getLatch().await(10000, TimeUnit.MILLISECONDS);
// receiver.receive(BOOT_TOPIC);
assertThat(receiver.getLatch().getCount()).isEqualTo(0);
}
}
I have defined the topics inside the application.yml as below-
spring:
kafka:
consumer:
auto-offset-reset: earliest
group-id: boot
kafka:
topic:
boot: boot.t
Inside ContainerTestUtils class inside waitForAssignment method with below call returns assignedPartitions = null
int count = 0;
....
Collection<?> assignedPartitions = (Collection<?>) getAssignedPartitions.invoke(aContainer);
if (assignedPartitions != null) {
count += assignedPartitions.size();
}
...
So the count above remains 0. But I get the assertion failure as below:
org.junit.ComparisonFailure: expected:<[2]> but was:<[0]>

Related

Spring kafka JsonSerializer to payload with map with null key throws exception

I have created a rest endpoint to push message to kafka, the details as follows
Data or message payload, used for example
package com.learn.kafka.model;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import lombok.Data;
import java.util.Map;
#Data
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "type")
public class SpecialData {
Map<String, Object> messageInfo;
}
consumer service with kafka listener
package com.learn.kafka.service;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
#Component
#Slf4j
public class ConsumerService {
#KafkaListener(topics={"#{'${spring.kafka.topic}'}"},groupId="#{'${spring.kafka.consumer.group-id}'}")
public void consumeMessage(String message){
log.info("Consumed message - {}",message);
}
}
producer service, that contains kafka template
package com.learn.kafka.service;
import java.text.MessageFormat;
import com.learn.kafka.model.SpecialData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.kafka.support.KafkaHeaders;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
#Service
#Slf4j
public class ProducerService{
#Value("${spring.kafka.topic:demo-topic}")
String topicName;
#Autowired
KafkaTemplate<String,Object> kafkaTemplate;
public String sendMessage(SpecialData messageModel){
log.info("Sending message from producer - {}",messageModel);
Message message = constructMessage(messageModel);
kafkaTemplate.send(message);
return MessageFormat.format("Message Sent from Producer - {0}",message);
}
private Message constructMessage(SpecialData messageModel) {
return MessageBuilder.withPayload(messageModel)
.setHeader(KafkaHeaders.TOPIC,topicName)
.setHeader("reason","for-Local-validation")
.build();
}
}
sample controller to send same message
package com.learn.kafka.controller;
import com.learn.kafka.model.SpecialData;
import com.learn.kafka.service.ProducerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.Map;
#RestController
#RequestMapping("/api")
#Slf4j
public class MessageController {
#Autowired
private ProducerService producerService;
#GetMapping("/send")
public void sendMessage(){
SpecialData messageData = new SpecialData();
Map<String,Object> input = new HashMap<>();
input.put(null,"the key is null explicitly");
input.put("1","the key is one non-null");
messageData.setMessageInfo(input);
producerService.sendMessage(messageData);
}
}
custom serializer
package com.learn.kafka;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.fasterxml.jackson.databind.util.StdDateFormat;
import org.apache.kafka.common.errors.SerializationException;
import org.apache.kafka.common.serialization.Serializer;
import java.io.IOException;
import java.util.Map;
public class CustomSerializer implements Serializer<Object> {
private static final ObjectMapper MAPPER = new ObjectMapper();
static {
MAPPER.findAndRegisterModules();
MAPPER.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
MAPPER.setDateFormat(new StdDateFormat().withColonInTimeZone(true));
MAPPER.getSerializerProvider().setNullKeySerializer(new NullKeyKeySerializer());
}
#Override
public void configure(Map<String, ?> configs, boolean isKey) {
}
#Override
public byte[] serialize(String topic, Object data) {
try {
if (data == null){
System.out.println("Null received at serializing");
return null;
}
System.out.println("Serializing...");
return MAPPER.writeValueAsBytes(data);
} catch (Exception e) {
e.printStackTrace();
throw new SerializationException("Error when serializing MessageDto to byte[]");
}
}
#Override
public void close() {
}
static class NullKeyKeySerializer extends StdSerializer<Object> {
public NullKeyKeySerializer() {
this(null);
}
public NullKeyKeySerializer(Class<Object> t) {
super(t);
}
#Override
public void serialize(Object obj, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeFieldName("null");
}
}
}
application.yaml
spring:
kafka:
topic: input-topic
consumer:
bootstrap-servers: localhost:9092
group-id: input-group-id
auto-offset-reset: earliest
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
producer:
bootstrap-servers: localhost:9092
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: com.learn.kafka.CustomSerializer
properties:
spring.json.add.type.headers: false
Above code works. I was able to serialize the SpecialData with null key in map and send to broker and receive the message. The consumer uses the String Deserializer, so it printed is as expected. But I think there will be issue when using simply the JsonDeSerializer.
Is there different approaches like,
Extend the existing spring JsonSerializer, just to add the NullKeySerializer to the ObjectMapper?
Simple configuration in the application.yaml?
Reference for null key serializer implementation
You don't need to extend the deserializer, it already has a constructor that takes a custom ObjectMapper; simply create one in Java and add it to the consumer factory using setValueDeserializer(). (There are similar setters for serializers on the producer factory).
However, extending the class will allow you to configure it in the yaml, if that is what you prefer.
Adding the code details to #Gary Russell answer above.
In my scenario I am ok with only serialization part of it. No issues since I don't want to de-serialize the payload and use specific data.
package com.learn.kafka;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.fasterxml.jackson.databind.util.StdDateFormat;
import org.springframework.kafka.support.serializer.JsonSerializer;
import java.io.IOException;
public class CustomJsonSerializer extends JsonSerializer<Object> {
public CustomJsonSerializer() {
super(customizedObjectMapper());
}
private static ObjectMapper customizedObjectMapper() {
ObjectMapper objMapper= new ObjectMapper();
//if the pay load include timestamps we need to use modules
objMapper.findAndRegisterModules();
objMapper.getSerializerProvider().setNullKeySerializer(new NullKeySerializer());
return objMapper;
}
static class NullKeySerializer extends StdSerializer<Object> {
public NullKeySerializer() {
this(null);
}
public NullKeySerializer(Class<Object> t) {
super(t);
}
#Override
public void serialize(Object nullKey, JsonGenerator generator, SerializerProvider unused)
throws IOException {
generator.writeFieldName("null");
}
}
}
Use the class in application.yaml in value-serializer
spring:
kafka:
bootstrap-servers: domain:9092
producer:
value-serializer: com.learn.kafka.CustomJsonSerialier

Junit tests are failing after I upgrade the spring boot dependencies

I have the following code that is running fine when I had spring boot dependencies 2.3.3.
class Details {
String pin;
State state;
}
class DetailsDto {
String pin;
StateDto stateDto;
}
class State {
}
class StateDto {
}
#Named
class TestClass {
private final StateConverter converter;
#Inject
public TestClass(StateConverter converter) {
this.converter= converter;
}
public DetailsDto getDetails(Details details) {
DetailsDto dto = new DetailsDto();
dto.setPin(details.getPin());
dto.setState(converter.convert(details.getState());
}
}
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
#RunWith(MockitoJUnitRunner.class)
public class TestClassTest {
#Mock
private StateConverter converter;
#InjectMocks
private TestClass testClass;
#Test
public final void testSomething() {
final String pin = "12345";
final State state = mock(State.class);
Details details = mock(Details.class);
given(details.getPin()).willReturn(pin);
given(details.getState()).willReturn(state);
StateDto stateDto = mock(StateDto.class);
given(converter.convert(state)).willReturn(stateDto);
DetailsDto deatilsDto = testClass.getDetails(details);
assertThat(deatilsDto.getPin(), equalTo(pin));
verify(converter).convert(state);
assertThat(deatilsDto.getState(), equalTo(stateDto));
}
}
The same test case I am running with spring boot dependencies 2.6.2 like this. The changes I have done are
I am using jupiter.api.test instead of junit.test, using ExtendWith instead of RunWith, using MockitoExtension instead of MockitoJUnitRunner
I am getting nullpointer exception when converter.convert is called
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
#ExtendWith(MockitoExtension.class)
public class TestClassTest {
#Mock
private StateConverter converter;
#InjectMocks
private TestClass testClass;
#Test
public final void testSomething() {
final String pin = "12345";
final State state = mock(State.class);
Details details = mock(Details.class);
given(details.getPin()).willReturn(pin);
given(details.getState()).willReturn(state);
StateDto stateDto = mock(StateDto.class);
given(converter.convert(state)).willReturn(stateDto);
DetailsDto deatilsDto = testClass.getDetails(details);
assertThat(deatilsDto.getPin(), equalTo(pin));
verify(converter).convert(state);
assertThat(deatilsDto.getState(), equalTo(stateDto));
}
}
This is due to using the wrong maven-surefire-plugin version
more at https://www.journaldev.com/21711/junit-setup-maven
junit5 tests need maven-surefire-plugin 2.22.0

Spring boot Kafka integration test: Consumer always returns 0 records

For the following test I am always getting the error:
org.opentest4j.AssertionFailedError: expected: 10 but was : 0
What exactly I am trying to verify in scope of the test:
I am trying to send 10 messages to Kafka and after that immediately I am trying to read those messages from Kafka, but for some unknown reason KafkaConsumer returns 0 records, and I am struggling to understand why Consumer can't read messages that were sent earlier?
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.kafka.KafkaProperties;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.stream.IntStream;
#SpringBootTest
#ActiveProfiles("test")
#ContextConfiguration(initializers = TestKafkaContextInitializer.class)
#Slf4j
public class KafkaFlowVerificationITest {
#Autowired
private KafkaTemplate<String, String> kafkaTemplate;
#Autowired
private KafkaProperties kafkaProperties;
private final String kafkaTopic = "test.topic";
#Test
void testKafkaFlow() {
IntStream.range(0, 10)
.forEach(e -> {
try {
kafkaTemplate.send(kafkaTopic, UUID.randomUUID().toString()).get();
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
}
});
checkKafkaForMessage();
}
private void checkKafkaForMessage() {
Map<String, Object> properties = new HashMap<>();
properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaProperties.getBootstrapServers());
properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, org.apache.kafka.common.serialization.StringDeserializer.class);
properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, org.apache.kafka.common.serialization.StringDeserializer.class);
properties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false");
properties.put(ConsumerConfig.GROUP_ID_CONFIG, "acme");
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(properties);
consumer.subscribe(List.of(kafkaTopic));
ConsumerRecords<String, String> records = consumer.poll(Duration.ZERO);
Assertions.assertThat(records.count()).isEqualTo(10);
}
}
and TestKafkaContextInitializer:
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.testcontainers.containers.KafkaContainer;
import org.testcontainers.utility.DockerImageName;
#Slf4j
public class TestKafkaContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
private final KafkaContainer kafkaContainer =
new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:5.4.3"));
#Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
kafkaContainer.start();
var values = TestPropertyValues.of(
"spring.kafka.producer.bootstrap-servers=" + kafkaContainer.getBootstrapServers(),
"spring.kafka.consumer.bootstrap-servers=" + kafkaContainer.getBootstrapServers()
);
values.applyTo(configurableApplicationContext);
}
}
The root cause of the issue is:
I set TestContainer Kafka bootstrap server url for the following properties:
spring.kafka.producer.bootstrap-servers
spring.kafka.consumer.bootstrap-servers
but in the test I use:
spring.kafka.bootstrap-servers property, that why Consumer made attempt connect to localhost:9092 default URL instead of URL provided by TestContainer.

Unable to Mock RestTemplate.exchange

As part of TDD i want to be able to test every portion of my SpringBoot rest application. However i am unable to mock external calls.
Application structure
1. Few rest endpoints which internally call external rest endpoints.
2. All calls to external endpoints are orchestrated through a local http client which utilizes RestTemplate as httpClient.
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.MOCK, classes = TestDrivenDevelopmentWithJavaApplication.class)
public class TestDrivenDevelopmentWithJavaApplicationTests {
#Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
#MockBean
private RestTemplate client;
#Before
public void setup() throws Exception {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
Structure1Root category = new Structure1Root();
Category cat = new Category();
cat.setCategoryName("Test1");
cat.setDescription("Test");
category.setD(cat);
Mockito.when(client.exchange(
ArgumentMatchers.eq("https://services.odata.org/V2/Northwind/Northwind.svc/Products(1)?$format=json"),
ArgumentMatchers.eq(HttpMethod.GET), ArgumentMatchers.eq(null),
ArgumentMatchers.eq(Structure1Root.class)))
.thenReturn(new ResponseEntity<Structure1Root>(category, HttpStatus.OK));
}
#Test
public void testendpoint1() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/api/endpoint1?token=1").contentType(MediaType.APPLICATION_JSON))
.andExpect(content().string(org.hamcrest.Matchers.containsString("Test1")));
}
}
Even though i have setup the mock on client.exchange(RestTemplate.exchange), i see response returned by client.exchange is null and not the response specified in thenReturn
Controller Code
#RestController
#RequestMapping(path = Endpoint.base)
public class Endpoint {
public static final String base = "/api";
#Autowired
MyHttpClient<Structure2Root> client;
#Autowired
MyHttpClient<Structure1Root> Cclient;
#GetMapping(path = "/endpoint1")
public ResponseEntity<Structure2Root> callEndpt1(#RequestParam String token) {
Response<Structure2Root> resp = client
.execute("https://services.odata.org/V2/Northwind/Northwind.svc/Products(1)?$format=json", Structure2Root.class);
return new ResponseEntity<Structure2Root>(resp.getResponse(), HttpStatus.OK);
}
#GetMapping(path = "/endpoint2")
public ResponseEntity<Structure1Root> callEndpt2(#RequestParam String token) {
Response<Structure1Root> resp = Cclient.execute(
"https://services.odata.org/V2/Northwind/Northwind.svc/Categories(1)?$format=json", Structure1Root.class);
return new ResponseEntity<Structure1Root>(resp.getResponse(),HttpStatus.OK);
}
}
And finally, local http client code
#Service
public class MyHttpClient<O> {
#Autowired
RestTemplate client;
public MyHttpClient() {
// TODO Auto-generated constructor stub
}
public Response<O> execute(String url, Class<O> generic) {
ResponseEntity<O> resp = client.exchange(url, HttpMethod.GET, null, generic);
return new Response<O>(resp.getStatusCode(), resp.getBody());
}
}
this client.execute is what i intend to intercept in the first code block
However never seems to work and always returns a null.
The Git Repo
Regards,
Veera
You have used the wrong object while mocking. You should be using Structure2Root rather then Structure1Root
The correct test class is below which is working perfectly fine.
package com.demo.samples.tdd;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import com.demo.samples.tdd.responses.Product;
import com.demo.samples.tdd.responses.Structure2Root;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.WebApplicationContext;
import com.demo.samples.tdd.responses.Category;
import com.demo.samples.tdd.responses.Structure1Root;
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.MOCK, classes = TestDrivenDevelopmentWithJavaApplication.class)
public class TestDrivenDevelopmentWithJavaApplicationTests {
#Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
#MockBean
private RestTemplate client;
#Before
public void setup() throws Exception {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
// Structure1Root category = new Structure1Root();
// Category cat = new Category();
// cat.setCategoryName("Test1");
// cat.setDescription("Test");
// category.setD(cat);
//
// Mockito.when(client.exchange(
// ArgumentMatchers.eq("https://services.odata.org/V2/Northwind/Northwind.svc/Products(1)?$format=json"),
// ArgumentMatchers.eq(HttpMethod.GET), ArgumentMatchers.eq(null),
// ArgumentMatchers.eq(Structure1Root.class)))
// .thenReturn(new ResponseEntity<Structure1Root>(category, HttpStatus.OK));
Structure2Root category2 = new Structure2Root();
Product product = new Product();
product.setProductName("Test1");
product.setUnitPrice("1");
category2.setD(product);
Mockito.when(client.exchange(
ArgumentMatchers.eq("https://services.odata.org/V2/Northwind/Northwind.svc/Products(1)?$format=json"),
ArgumentMatchers.eq(HttpMethod.GET), ArgumentMatchers.eq(null),
ArgumentMatchers.eq(Structure2Root.class)))
.thenReturn(new ResponseEntity<Structure2Root>(category2, HttpStatus.OK));
}
#Test
public void testendpoint1() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/api/endpoint1?token=1").contentType(MediaType.APPLICATION_JSON))
.andExpect(content().string(org.hamcrest.Matchers.containsString("Test1")));
}
}

Need an example on Embedded kafka with camel

I am facing issue while testing kafka with camel. I used Embedded kafka with camel and here's what I tried
I have tried this example which tells us about testing kafka using embedded kafka
https://codenotfound.com/spring-kafka-embedded-unit-test-example.html
package com.codenotfound.kafka.producer;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertThat;
import static org.springframework.kafka.test.assertj.KafkaConditions.key;
import static org.springframework.kafka.test.hamcrest.KafkaMatchers.hasValue;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.main.Main;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
import org.springframework.kafka.listener.ContainerProperties;
import org.springframework.kafka.listener.KafkaMessageListenerContainer;
import org.springframework.kafka.listener.MessageListener;
import org.springframework.kafka.test.rule.EmbeddedKafkaRule;
import org.springframework.kafka.test.utils.ContainerTestUtils;
import org.springframework.kafka.test.utils.KafkaTestUtils;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#SpringBootTest
#DirtiesContext
public class SpringKafkaSenderTest {
private static final Logger LOGGER = LoggerFactory.getLogger(SpringKafkaSenderTest.class);
private static String SENDER_TOPIC = "sender.t";
#Autowired
private Sender sender;
private KafkaMessageListenerContainer<String, String> container;
private BlockingQueue<ConsumerRecord<String, String>> records;
Object groupId;
Object bootstrapServers;
#ClassRule
public static EmbeddedKafkaRule embeddedKafka = new EmbeddedKafkaRule(1, true, SENDER_TOPIC);
#Before
public void setUp() throws Exception {
// set up the Kafka consumer properties
Map<String, Object> consumerProperties = KafkaTestUtils.consumerProps("sender", "false",
embeddedKafka.getEmbeddedKafka());
for (Entry<String, Object> entry : consumerProperties.entrySet()) {
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
if (entry.getKey().equals("group.id")) {
groupId = entry.getValue();
} else if (entry.getKey().equals("bootstrap.servers")) {
bootstrapServers = entry.getValue();
}
}
// create a Kafka consumer factory
DefaultKafkaConsumerFactory<String, String> consumerFactory = new DefaultKafkaConsumerFactory<String, String>(
consumerProperties);
// set the topic that needs to be consumed
ContainerProperties containerProperties = new ContainerProperties(SENDER_TOPIC);
// create a Kafka MessageListenerContainer
container = new KafkaMessageListenerContainer<>(consumerFactory, containerProperties);
// create a thread safe queue to store the received message
records = new LinkedBlockingQueue<>();
// setup a Kafka message listener
container.setupMessageListener(new MessageListener<String, String>() {
#Override
public void onMessage(ConsumerRecord<String, String> record) {
LOGGER.debug("test-listener received message='{}'", record.toString());
records.add(record);
}
});
// start the container and underlying message listener
container.start();
// wait until the container has the required number of assigned partitions
ContainerTestUtils.waitForAssignment(container, embeddedKafka.getEmbeddedKafka().getPartitionsPerTopic());
}
#After
public void tearDown() {
// stop the container
container.stop();
}
#Test
public void testCamelWithKafka() throws Exception {
String topicName = "topic=javainuse-topic";
String kafkaServer = "kafka:localhost:9092";
String zooKeeperHost = "zookeeperHost=localhost&zookeeperPort=2181";
String serializerClass = "serializerClass=kafka.serializer.StringEncoder";
String toKafka = new StringBuilder().append(kafkaServer).append("?").append(topicName).append("&")
.append(zooKeeperHost).append("&").append(serializerClass).toString();
String embedded = new StringBuilder().append(bootstrapServers).append("?").append(topicName).append("&")
// .append(embeddedKafka.getEmbeddedKafka().getZookeeperConnectionString())
.append(zooKeeperHost).append("&").append(serializerClass).toString();
Main main = new Main();
main.addRouteBuilder(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("file:D://inbox//?noop=true").split().tokenize("\n").to("direct:embedded");
}
});
main.run();
ConsumerRecord<String, String> received =
records.poll(10, TimeUnit.SECONDS);
// assertThat(received, hasValue(greeting));
// AssertJ Condition to check the key
// assertThat(received).has(key(null));
// System.out.println(received);
}
}
Camel should able to read from a file and move the data to kafka and consumer should able to read it.
You can use the #Runwith(CamelSpringBootRunner.class) to run the test case.

Resources