package com.xiaomi.infra.galaxy.talos.storm;
import backtype.storm.spout.SpoutOutputCollector;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.xiaomi.infra.galaxy.talos.consumer.MessageCheckpointer;
import com.xiaomi.infra.galaxy.talos.storm.config.TalosStormConfig;
import com.xiaomi.infra.galaxy.talos.storm.message.PartitionMessagePool;
import com.xiaomi.infra.galaxy.talos.storm.message.TalosStormMessage;
import com.xiaomi.infra.galaxy.talos.storm.message.TalosStormMessageProcessor;
import com.xiaomi.infra.galaxy.talos.thrift.Message;
import com.xiaomi.infra.galaxy.talos.thrift.MessageAndOffset;
import com.xiaomi.infra.galaxy.talos.thrift.TopicAndPartition;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
/**
* Created by jiasheng on 16-6-7.
*/
public class TalosStormSpoutTest {
@Mock
private SpoutOutputCollector collector;
@Mock
private TalosStormMessageProcessor msgProcessor;
@Mock
private PartitionMessagePool msgPool;
@Mock
private MessageCheckpointer msgCkp;
private ConcurrentHashMap<String, TalosStormMessageProcessor> msgProcessors;
private TalosStormSpout talosStormSpout;
private static final String topic = "test-topic";
private static final int partition = 0;
private static final String message = "test-message";
private static final long offset = 123l;
private static final long commitInterval = 1000l;
@Before
public void prepare() throws Exception {
MockitoAnnotations.initMocks(this);
talosStormSpout = new TalosStormSpout(new TalosStormConfig(topic, "", null, null));
msgProcessors = new ConcurrentHashMap<String, TalosStormMessageProcessor>();
msgProcessors.put(Joiner.on("-").join(topic, partition), msgProcessor);
prepareTalosStormSpout();
prepareMessageProcessor();
prepareMessagePool();
prepareMessageCheckpointer();
prepareOutputCollector();
}
private void prepareTalosStormSpout() throws NoSuchFieldException, IllegalAccessException {
Field collectorField = TalosStormSpout.class.getDeclaredField("collector");
collectorField.setAccessible(true);
collectorField.set(talosStormSpout, collector);
Field processorsField = TalosStormSpout.class.getDeclaredField("msgProcessors");
processorsField.setAccessible(true);
processorsField.set(talosStormSpout, msgProcessors);
Field commitIntervalField = TalosStormSpout.class.getDeclaredField("commitIntervalMs");
commitIntervalField.setAccessible(true);
commitIntervalField.set(talosStormSpout, commitInterval);
}
private void prepareMessageProcessor() {
when(msgProcessor.getMessagePool()).thenReturn(Optional.of(msgPool));
when(msgProcessor.getMessageCheckpointer()).thenReturn(Optional.of(msgCkp));
when(msgProcessor.getTopicPartition()).thenReturn(Optional.of(new TopicAndPartition(topic, null, partition)));
}
private void prepareMessagePool() {
when(msgPool.get()).thenReturn(Optional.of(new TalosStormMessage(
new TopicAndPartition(topic, null, partition),
new MessageAndOffset(new Message(ByteBuffer.wrap(message.getBytes())), offset)
)));
when(msgPool.getCommitOffset()).thenReturn(Optional.of(offset));
}
private void prepareMessageCheckpointer() {
when(msgCkp.checkpoint(anyLong())).thenReturn(true);
}
private void prepareOutputCollector() {
when(collector.emit(anyList(), anyString())).thenReturn(null);
}
@Test
public void testEmitAndCommit() throws InterruptedException {
talosStormSpout.nextTuple();
Thread.sleep(commitInterval);
talosStormSpout.nextTuple();
ArgumentCaptor<List> tupleCaptor = ArgumentCaptor.forClass(List.class);
verify(collector, atLeastOnce()).emit(tupleCaptor.capture(), anyString());
List tuple = tupleCaptor.getValue();
assertEquals(message, tuple.get(0));
assertEquals(offset, tuple.get(1));
assertEquals(topic, tuple.get(2));
assertEquals(partition, tuple.get(3));
ArgumentCaptor<Long> offsetCaptor = ArgumentCaptor.forClass(Long.class);
verify(msgCkp).checkpoint(offsetCaptor.capture());
assertEquals(offset, offsetCaptor.getValue().longValue());
}
}