/*
* Copyright 2014 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.xd.shell.command;
import static org.junit.Assert.assertThat;
import static org.springframework.xd.shell.command.fixtures.XDMatchers.eventually;
import static org.springframework.xd.shell.command.fixtures.XDMatchers.exists;
import static org.springframework.xd.shell.command.fixtures.XDMatchers.hasValue;
import java.util.Collections;
import java.util.Properties;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.integration.kafka.core.TopicNotFoundException;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.xd.shell.command.fixtures.HttpSource;
import org.springframework.xd.test.fixtures.CounterSink;
import org.springframework.xd.test.kafka.KafkaTestSupport;
import kafka.admin.AdminUtils;
import kafka.api.TopicMetadata;
/**
* Integration tests for Kafka source and sinks.
*
* @author Ilayaperumal Gopinathan
* @author Marius Bogoevici
* @since 1.1
*/
public class AbstractKafkaSourceSinkTests extends AbstractStreamIntegrationTest {
private String topic1ToUse;
private String topic2ToUse;
@Rule
public KafkaTestSupport kafkaTestSupport = new KafkaTestSupport();
@Before
public void createTopic() throws Exception {
topic1ToUse = "kafka-test-topic-" + random.nextInt();
// create Kafka topic
AdminUtils.createTopic(kafkaTestSupport.getZkClient(), topic1ToUse, 1, 1, new Properties());
setupRetryTemplate(topic1ToUse);
}
private void setupRetryTemplate(final String topic) throws Exception {
RetryTemplate retryTemplate = new RetryTemplate();
retryTemplate.setRetryPolicy(new SimpleRetryPolicy(5,
Collections.<Class<? extends Throwable>,Boolean>singletonMap(TopicNotFoundException.class, true)));
retryTemplate.setBackOffPolicy(new ExponentialBackOffPolicy());
retryTemplate.execute(new RetryCallback<TopicMetadata, Exception>() {
@Override
public TopicMetadata doWithRetry(RetryContext context) throws Exception {
return AdminUtils.fetchTopicMetadataFromZk(topic, kafkaTestSupport.getZkClient());
}
});
}
@After
public void deleteTopic() {
// delete topic
AdminUtils.deleteTopic(kafkaTestSupport.getZkClient(), topic1ToUse);
}
@Test
public void testKafkaSourceAndSink() throws Exception {
final String stringToPost = "Hi there!";
// create stream with kafka sink
final HttpSource httpSource = newHttpSource();
stream().create(generateStreamName(), "%s | kafka --topic='%s' --brokerList='%s'",
httpSource, topic1ToUse, kafkaTestSupport.getBrokerAddress());
// create stream with kafka source
final CounterSink counter = metrics().newCounterSink();
stream().create(generateStreamName(), "kafka --topic='%s' --zkconnect=%s --outputType=text/plain | " +
"filter --expression=payload.toString().contains('%s') | %s",
topic1ToUse, kafkaTestSupport.getZkConnectString(), stringToPost, counter );
httpSource.ensureReady().postData(stringToPost);
assertThat(counter, eventually(exists()));
}
@Test
public void testKafkaSourceAndSinkWithMultiTopics() throws Exception {
topic2ToUse = "kafka-test-topic-" + random.nextInt();
AdminUtils.createTopic(kafkaTestSupport.getZkClient(), topic2ToUse, 1, 1, new Properties());
setupRetryTemplate(topic2ToUse);
final String stringToPost = "Hi there!";
// create stream with kafka sink
final HttpSource httpSource1 = newHttpSource();
final HttpSource httpSource2 = newHttpSource();
stream().create(generateStreamName(), "%s | kafka --topic='%s' --brokerList='%s'",
httpSource1, topic1ToUse, kafkaTestSupport.getBrokerAddress());
stream().create(generateStreamName(), "%s | kafka --topic='%s' --brokerList='%s'",
httpSource2, topic2ToUse, kafkaTestSupport.getBrokerAddress());
// create stream with kafka source
final CounterSink counter = metrics().newCounterSink();
stream().create(generateStreamName(), "kafka --topics='%s,%s' --zkconnect=%s --outputType=text/plain | " +
"filter --expression=payload.toString().contains('%s') | %s",
topic1ToUse, topic2ToUse, kafkaTestSupport.getZkConnectString(), stringToPost, counter );
httpSource1.ensureReady().postData(stringToPost);
httpSource2.ensureReady().postData(stringToPost);
assertThat(counter, eventually(exists()));
assertThat(counter, eventually(hasValue("2")));
AdminUtils.deleteTopic(kafkaTestSupport.getZkClient(), topic2ToUse);
}
}