package com.linkedin.camus.etl.kafka.mapred;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
import kafka.common.ErrorMapping;
import kafka.javaapi.PartitionMetadata;
import kafka.javaapi.TopicMetadata;
import kafka.javaapi.TopicMetadataRequest;
import kafka.javaapi.TopicMetadataResponse;
import kafka.javaapi.consumer.SimpleConsumer;
import org.apache.hadoop.mapreduce.JobContext;
import org.apache.log4j.Logger;
import org.easymock.EasyMock;
import org.apache.hadoop.conf.Configuration;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
public class EtlInputFormatTest {
private static final String DUMMY_VALUE = "dummy:1234";
@Test
public void testEmptyWhitelistBlacklistEntries() {
Configuration conf = new Configuration();
conf.set(EtlInputFormat.KAFKA_WHITELIST_TOPIC, ",TopicA,TopicB,,TopicC,");
conf.set(EtlInputFormat.KAFKA_BLACKLIST_TOPIC, ",TopicD,TopicE,,,,,TopicF,");
String[] whitelistTopics = EtlInputFormat.getKafkaWhitelistTopic(conf);
Assert.assertEquals(Arrays.asList("TopicA", "TopicB", "TopicC"), Arrays.asList(whitelistTopics));
String[] blacklistTopics = EtlInputFormat.getKafkaBlacklistTopic(conf);
Assert.assertEquals(Arrays.asList("TopicD", "TopicE", "TopicF"), Arrays.asList(blacklistTopics));
}
@Test
public void testWithOneRetry() {
List<Object> mocks = new ArrayList<Object>();
Configuration configuration = EasyMock.createMock(Configuration.class);
mocks.add(configuration);
EasyMock.expect(configuration.get(EasyMock.anyString())).andReturn(DUMMY_VALUE).anyTimes();
JobContext jobContext = EasyMock.createMock(JobContext.class);
mocks.add(jobContext);
EasyMock.expect(jobContext.getConfiguration()).andReturn(configuration).anyTimes();
List<TopicMetadata> topicMetadatas = new ArrayList<TopicMetadata>();
TopicMetadataResponse topicMetadataResponse = EasyMock.createMock(TopicMetadataResponse.class);
mocks.add(topicMetadataResponse);
EasyMock.expect(topicMetadataResponse.topicsMetadata()).andReturn(topicMetadatas);
SimpleConsumer simpleConsumer = EasyMock.createMock(SimpleConsumer.class);
mocks.add(simpleConsumer);
EasyMock.expect(simpleConsumer.clientId()).andReturn(DUMMY_VALUE).times(2);
EasyMock.expect(simpleConsumer.send((TopicMetadataRequest) EasyMock.anyObject())).andThrow(
new RuntimeException("No TopicMD"));
EasyMock.expect(simpleConsumer.send((TopicMetadataRequest) EasyMock.anyObject())).andReturn(topicMetadataResponse);
simpleConsumer.close();
EasyMock.expectLastCall().andVoid().anyTimes();
EasyMock.replay(mocks.toArray());
EtlInputFormat inputFormat = new EtlInputFormatForUnitTest();
EtlInputFormatForUnitTest.consumerType = EtlInputFormatForUnitTest.ConsumerType.MOCK;
EtlInputFormatForUnitTest.consumer = simpleConsumer;
List<TopicMetadata> actualTopicMetadatas = inputFormat.getKafkaMetadata(jobContext, new ArrayList<String>());
EasyMock.verify(mocks.toArray());
assertEquals(actualTopicMetadatas, topicMetadatas);
}
@Test(expected = RuntimeException.class)
public void testWithThreeRetries() {
List<Object> mocks = new ArrayList<Object>();
Configuration configuration = EasyMock.createMock(Configuration.class);
mocks.add(configuration);
EasyMock.expect(configuration.get(EasyMock.anyString())).andReturn(DUMMY_VALUE).anyTimes();
JobContext jobContext = EasyMock.createMock(JobContext.class);
mocks.add(jobContext);
EasyMock.expect(jobContext.getConfiguration()).andReturn(configuration).anyTimes();
SimpleConsumer simpleConsumer = EasyMock.createMock(SimpleConsumer.class);
mocks.add(simpleConsumer);
EasyMock.expect(simpleConsumer.clientId()).andReturn(DUMMY_VALUE)
.times(EtlInputFormat.NUM_TRIES_TOPIC_METADATA + 1);
Exception ex = new RuntimeException("No TopicMeta");
EasyMock.expect(simpleConsumer.send((TopicMetadataRequest) EasyMock.anyObject())).andThrow(ex)
.times(EtlInputFormat.NUM_TRIES_TOPIC_METADATA);
simpleConsumer.close();
EasyMock.expectLastCall().andVoid().anyTimes();
EasyMock.replay(mocks.toArray());
EtlInputFormat inputFormat = new EtlInputFormatForUnitTest();
EtlInputFormatForUnitTest.consumerType = EtlInputFormatForUnitTest.ConsumerType.MOCK;
EtlInputFormatForUnitTest.consumer = simpleConsumer;
List<TopicMetadata> actualTopicMetadatas = inputFormat.getKafkaMetadata(jobContext, new ArrayList<String>());
EasyMock.verify(mocks.toArray());
}
/**
* Test only refreshing the paritionMetadata when the error code is LeaderNotAvailable.
* @throws Exception
*/
@Test
public void testRefreshPartitioMetadataOnLeaderNotAvailable() throws Exception {
JobContext dummyContext = null;
//A partitionMetadata with errorCode LeaderNotAvailable
PartitionMetadata partitionMetadata1 = createMock(PartitionMetadata.class);
expect(partitionMetadata1.errorCode()).andReturn(ErrorMapping.LeaderNotAvailableCode());
expect(partitionMetadata1.partitionId()).andReturn(0);
replay(partitionMetadata1);
//A partitionMetadata with errorCode not LeaderNotAvailable
PartitionMetadata partitionMetadata2 = createMock(PartitionMetadata.class);
expect(partitionMetadata2.errorCode()).andReturn(ErrorMapping.InvalidMessageCode());
expect(partitionMetadata2.partitionId()).andReturn(0);
replay(partitionMetadata2);
PartitionMetadata mockedReturnedPartitionMetadata = createMock(PartitionMetadata.class);
expect(mockedReturnedPartitionMetadata.errorCode()).andReturn(ErrorMapping.NoError());
expect(mockedReturnedPartitionMetadata.partitionId()).andReturn(0);
replay(mockedReturnedPartitionMetadata);
TopicMetadata mockedTopicMetadata = createMock(TopicMetadata.class);
expect(mockedTopicMetadata.topic()).andReturn("testTopic");
expect(mockedTopicMetadata.partitionsMetadata()).andReturn(
Collections.singletonList(mockedReturnedPartitionMetadata));
replay(mockedTopicMetadata);
EtlInputFormat etlInputFormat =
createMock(EtlInputFormat.class,
EtlInputFormat.class.getMethod("getKafkaMetadata", new Class[] { JobContext.class, List.class }));
EasyMock.expect(etlInputFormat.getKafkaMetadata(dummyContext, Collections.singletonList("testTopic"))).andReturn(
Collections.singletonList(mockedTopicMetadata));
etlInputFormat.setLogger(Logger.getLogger(getClass()));
replay(etlInputFormat);
// For partitionMetadata2, it will not refresh if the errorcode is not LeaderNotAvailable.
assertEquals(partitionMetadata2, etlInputFormat.refreshPartitionMetadataOnLeaderNotAvailable(partitionMetadata2,
mockedTopicMetadata, dummyContext, EtlInputFormat.NUM_TRIES_PARTITION_METADATA));
// For partitionMetadata1, it will refresh if the errorcode is LeaderNotAvailable.
assertEquals(mockedReturnedPartitionMetadata, etlInputFormat.refreshPartitionMetadataOnLeaderNotAvailable(
partitionMetadata1, mockedTopicMetadata, dummyContext, EtlInputFormat.NUM_TRIES_PARTITION_METADATA));
}
/**
* Test only refreshing the paritionMetadata when the error code is LeaderNotAvailable.
* @throws Exception
*/
@Test
public void testRefreshPartitioMetadataWithThreeRetries() throws Exception {
JobContext dummyContext = null;
//A partitionMetadata with errorCode LeaderNotAvailable
PartitionMetadata partitionMetadata = createMock(PartitionMetadata.class);
expect(partitionMetadata.errorCode()).andReturn(ErrorMapping.LeaderNotAvailableCode()).times(EtlInputFormat.NUM_TRIES_PARTITION_METADATA * 2);
expect(partitionMetadata.partitionId()).andReturn(0).times(EtlInputFormat.NUM_TRIES_PARTITION_METADATA * 2);
replay(partitionMetadata);
TopicMetadata mockedTopicMetadata = createMock(TopicMetadata.class);
expect(mockedTopicMetadata.topic()).andReturn("testTopic").times(EtlInputFormat.NUM_TRIES_PARTITION_METADATA);
expect(mockedTopicMetadata.partitionsMetadata()).andReturn(Collections.singletonList(partitionMetadata)).times(
EtlInputFormat.NUM_TRIES_PARTITION_METADATA);
replay(mockedTopicMetadata);
EtlInputFormat etlInputFormat =
createMock(EtlInputFormat.class,
EtlInputFormat.class.getMethod("getKafkaMetadata", new Class[] { JobContext.class, List.class }));
EasyMock.expect(etlInputFormat.getKafkaMetadata(dummyContext, Collections.singletonList("testTopic"))).andReturn(
Collections.singletonList(mockedTopicMetadata)).times(EtlInputFormat.NUM_TRIES_PARTITION_METADATA);
etlInputFormat.setLogger(Logger.getLogger(getClass()));
replay(etlInputFormat);
etlInputFormat.refreshPartitionMetadataOnLeaderNotAvailable(partitionMetadata, mockedTopicMetadata, dummyContext,
EtlInputFormat.NUM_TRIES_PARTITION_METADATA);
verify(mockedTopicMetadata);
verify(etlInputFormat);
}
@After
public void after() {
EtlInputFormatForUnitTest.consumerType = EtlInputFormatForUnitTest.ConsumerType.REGULAR;
}
}